diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
index ba41787f64..b078e7689e 100644
--- a/drivers/pci/Kconfig
+++ b/drivers/pci/Kconfig
@@ -97,6 +97,15 @@ config PCIE_DW_MVEBU
 	  Armada-8K SoCs. The PCIe controller on Armada-8K is based on
 	  DesignWare hardware.
 
+config PCIE_SIFIVE_FU740
+	bool "Enable SiFive FU740 PCIe"
+	depends on CLK_SIFIVE_PRCI
+	depends on RESET_SIFIVE
+	depends on SIFIVE_GPIO
+	help
+	  Say Y here if you want to enable PCIe controller support on
+	  FU740.
+
 config PCIE_FSL
 	bool "FSL PowerPC PCIe support"
 	depends on DM_PCI
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
index 5ed94bc95c..5400d59cc5 100644
--- a/drivers/pci/Makefile
+++ b/drivers/pci/Makefile
@@ -51,3 +51,4 @@ obj-$(CONFIG_PCIE_ROCKCHIP) += pcie_rockchip.o
 obj-$(CONFIG_PCIE_DW_ROCKCHIP) += pcie_dw_rockchip.o
 obj-$(CONFIG_PCI_BRCMSTB) += pcie_brcmstb.o
 obj-$(CONFIG_PCI_OCTEONTX) += pci_octeontx.o
+obj-$(CONFIG_PCIE_SIFIVE_FU740) += pcie_sifive.o
diff --git a/drivers/pci/pcie_sifive.c b/drivers/pci/pcie_sifive.c
new file mode 100644
index 0000000000..ada60876bc
--- /dev/null
+++ b/drivers/pci/pcie_sifive.c
@@ -0,0 +1,797 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * SiFive FU740 DesignWare PCIe Controller
+ *
+ * Copyright (C) 2020-2021 SiFive, Inc.
+ *
+ * Based in early part on the i.MX6 PCIe host controller shim which is:
+ *
+ * Copyright (C) 2013 Kosagi
+ *		http://www.kosagi.com
+ *
+ * Based on driver from author: Alan Mikhak <amikhak@wirelessfabric.com>
+ */
+#include "pcie_sifive.h"
+#include <common.h>
+#include <dm.h>
+
+/* Host Bridge Identification */
+#define DEVICE_NAME	"SiFive FU740 PCIe Host Controller"
+#define VENDOR_ID	0x51fe
+#define DEVICE_ID	0x51fe
+
+static enum pcie_sifive_devtype pcie_sifive_get_devtype(struct pcie_sifive *sv)
+{
+	u32 val;
+
+	val = readl(sv->priv.iobase + MGMT_MISC_DEVICE_TYPE_OFFSET);
+	switch (val) {
+	case MGMT_MISC_DEVICE_TYPE_RC:
+		return SV_PCIE_HOST_TYPE;
+	case MGMT_MISC_DEVICE_TYPE_EP:
+		return SV_PCIE_ENDPOINT_TYPE;
+	default:
+		return SV_PCIE_UNKNOWN_TYPE;
+	}
+}
+
+static void pcie_sifive_priv_set_state(struct pcie_sifive *sv, u32 reg,
+				       u32 bits, int state)
+{
+	u32 val;
+
+	val = readl(sv->priv.iobase + reg);
+	val = state ? (val | bits) : (val & !bits);
+	writel(val, sv->priv.iobase + reg);
+}
+
+static void pcie_sifive_assert_perstn(struct pcie_sifive *sv)
+{
+	dm_gpio_set_value(&sv->perstn_gpio, 0);
+	writel(0x0, sv->priv.iobase + PCIEX8MGMT_PERST_N);
+	mdelay(100);
+}
+
+static void pcie_sifive_power_on(struct pcie_sifive *sv)
+{
+	dm_gpio_set_value(&sv->pwren_gpio, 1);
+	mdelay(100);
+}
+
+static void pcie_sifive_deassert_perstn(struct pcie_sifive *sv)
+{
+	writel(0x1, sv->priv.iobase + PCIEX8MGMT_PERST_N);
+	dm_gpio_set_value(&sv->perstn_gpio, 1);
+	mdelay(100);
+}
+
+static int pcie_sifive_setphy(const u8 phy, const u8 write,
+			      const u16 addr, const u16 wrdata,
+			      u16 *rddata, struct pcie_sifive *sv)
+{
+	unsigned char ack = 0;
+
+	if (!(phy == 0 || phy == 1))
+		return -2;
+
+	/* setup phy para */
+	writel(addr, sv->priv.iobase +
+	       (phy ? PCIEX8MGMT_PHY1_CR_PARA_ADDR :
+		PCIEX8MGMT_PHY0_CR_PARA_ADDR));
+
+	if (write)
+		writel(wrdata, sv->priv.iobase +
+		       (phy ? PCIEX8MGMT_PHY1_CR_PARA_WR_DATA :
+			PCIEX8MGMT_PHY0_CR_PARA_WR_DATA));
+
+	/* enable access if write */
+	if (write)
+		writel(1, sv->priv.iobase +
+		       (phy ? PCIEX8MGMT_PHY1_CR_PARA_WR_EN :
+			PCIEX8MGMT_PHY0_CR_PARA_WR_EN));
+	else
+		writel(1, sv->priv.iobase +
+		       (phy ? PCIEX8MGMT_PHY1_CR_PARA_RD_EN :
+			PCIEX8MGMT_PHY0_CR_PARA_RD_EN));
+
+	/* wait for wait_idle */
+	do {
+		u32 val;
+
+		val = readl(sv->priv.iobase +
+			    (phy ? PCIEX8MGMT_PHY1_CR_PARA_ACK :
+			     PCIEX8MGMT_PHY0_CR_PARA_ACK));
+		if (val) {
+			ack = 1;
+			if (!write)
+				readl(sv->priv.iobase +
+				      (phy ? PCIEX8MGMT_PHY1_CR_PARA_RD_DATA :
+				       PCIEX8MGMT_PHY0_CR_PARA_RD_DATA));
+			mdelay(1);
+		}
+	} while (!ack);
+
+	/* clear */
+	if (write)
+		writel(0, sv->priv.iobase +
+		       (phy ? PCIEX8MGMT_PHY1_CR_PARA_WR_EN :
+			PCIEX8MGMT_PHY0_CR_PARA_WR_EN));
+	else
+		writel(0, sv->priv.iobase +
+		       (phy ? PCIEX8MGMT_PHY1_CR_PARA_RD_EN :
+			PCIEX8MGMT_PHY0_CR_PARA_RD_EN));
+
+	while (readl(sv->priv.iobase +
+		     (phy ? PCIEX8MGMT_PHY1_CR_PARA_ACK :
+		      PCIEX8MGMT_PHY0_CR_PARA_ACK))) {
+		/* wait for ~wait_idle */
+	}
+
+	return 0;
+}
+
+static void pcie_sifive_init_phy(struct pcie_sifive *sv)
+{
+	int lane;
+
+	/* enable phy cr_para_sel interfaces */
+	writel(0x1, sv->priv.iobase + PCIEX8MGMT_PHY0_CR_PARA_SEL);
+	writel(0x1, sv->priv.iobase + PCIEX8MGMT_PHY1_CR_PARA_SEL);
+	mdelay(1);
+
+	/* set PHY AC termination mode */
+	for (lane = 0; lane < PCIEX8MGMT_LANE_NUM; lane++) {
+		pcie_sifive_setphy(0, 1,
+				   PCIEX8MGMT_LANE +
+				   (PCIEX8MGMT_LANE_OFF * lane),
+				   PCIEX8MGMT_TERM_MODE, NULL, sv);
+		pcie_sifive_setphy(1, 1,
+				   PCIEX8MGMT_LANE +
+				   (PCIEX8MGMT_LANE_OFF * lane),
+				   PCIEX8MGMT_TERM_MODE, NULL, sv);
+	}
+}
+
+static void pcie_sifive_set_pci_int_pin(struct pcie_sifive *sv,
+					enum pci_interrupt_pin pin)
+{
+	u32 val;
+
+	/* ctrl_ro_wr_enable */
+	val = readl(sv->ctrl.iobase + PCIE_MISC_CONTROL_1);
+	val |= DBI_RO_WR_EN;
+	writel(val, sv->ctrl.iobase + PCIE_MISC_CONTROL_1);
+
+	writeb(pin, sv->ctrl.iobase + PCI_CONFIG(PCI_INTERRUPT_PIN));
+
+	/* ctrl_ro_wr_disable */
+	val &= ~DBI_RO_WR_EN;
+	writel(val, sv->ctrl.iobase + PCIE_MISC_CONTROL_1);
+}
+
+static int pcie_sifive_get_property(struct pcie_sifive *sv,
+				    const char *property)
+{
+	u32 value = 0;
+
+	if (dev_read_u32(sv->pci.dev, property, &value))
+		return 0;
+
+	return value;
+}
+
+static int pcie_sifive_get_required_property(struct pcie_sifive *sv,
+					     const char *property)
+{
+	int value;
+
+	value = pcie_sifive_get_property(sv, property);
+	if (value == -EINVAL)
+		sv_err(sv, "Unable to read %s property\n", property);
+
+	return value;
+}
+
+static u32 pcie_sifive_get_link_width_mask(struct pcie_sifive *sv, int lanes)
+{
+	switch (lanes) {
+	case 1: return LINK_WIDTH_1_LANE;
+	case 2: return LINK_WIDTH_2_LANES;
+	case 4: return LINK_WIDTH_4_LANES;
+	case 8: return LINK_WIDTH_8_LANES;
+	default: return 0;
+	}
+}
+
+static u32 pcie_sifive_get_link_lanes_mask(struct pcie_sifive *sv, int lanes)
+{
+	switch (lanes) {
+	case 1: return LINK_MODE_1_LANE;
+	case 2: return LINK_MODE_2_LANES;
+	case 4: return LINK_MODE_4_LANES;
+	case 8: return LINK_MODE_8_LANES;
+	default: return 0;
+	}
+}
+
+static void pcie_sifive_set_link_num_lanes(struct pcie_sifive *sv, int lanes)
+{
+	u32 mode;
+
+	mode = pcie_sifive_get_link_lanes_mask(sv, lanes);
+	if (mode) {
+		u32 val;
+
+		val = readl(sv->ctrl.iobase + LINK_CONTROL);
+		val &= ~LINK_MODE_MASK;
+		val |= mode;
+		writel(val, sv->ctrl.iobase + LINK_CONTROL);
+	}
+}
+
+static void pcie_sifive_set_link_width(struct pcie_sifive *sv, int lanes)
+{
+	u32 lwidth;
+
+	lwidth = pcie_sifive_get_link_width_mask(sv, lanes);
+	if (lwidth) {
+		u32 val;
+
+		val = readl(sv->ctrl.iobase + LINK_WIDTH_SPEED_CONTROL);
+		val &= ~LINK_WIDTH_MASK;
+		val |= lwidth;
+		writel(val, sv->ctrl.iobase + LINK_WIDTH_SPEED_CONTROL);
+	}
+}
+
+static int pcie_sifive_check_link(struct pcie_sifive *sv)
+{
+	u32 val;
+
+	val = readl(sv->ctrl.iobase + PHY_DEBUG_R1);
+	return (val & PHY_DEBUG_R1_LINK_UP) &&
+		!(val & PHY_DEBUG_R1_LINK_IN_TRAINING);
+}
+
+static void pcie_sifive_force_gen1(struct pcie_sifive *sv)
+{
+	u32 val, linkcap;
+
+	/*
+	 * Force Gen1 operation when starting the link. In case the link is
+	 * started in Gen2 mode, there is a possibility the devices on the
+	 * bus will not be detected at all. This happens with PCIe switches.
+	 */
+
+	/* ctrl_ro_wr_enable */
+	val = readl(sv->ctrl.iobase + PCIE_MISC_CONTROL_1);
+	val |= DBI_RO_WR_EN;
+	writel(val, sv->ctrl.iobase + PCIE_MISC_CONTROL_1);
+
+	/* configure link cap */
+	linkcap = readl(sv->ctrl.iobase + PF0_PCIE_CAP_LINK_CAP);
+	linkcap |= PCIE_LINK_CAP_MAX_SPEED_MASK;
+	writel(linkcap, sv->ctrl.iobase + PF0_PCIE_CAP_LINK_CAP);
+
+	/* ctrl_ro_wr_disable */
+	val &= ~DBI_RO_WR_EN;
+	writel(val, sv->ctrl.iobase + PCIE_MISC_CONTROL_1);
+}
+
+static void pcie_sifive_print_phy_debug(struct pcie_sifive *sv)
+{
+	sv_err(sv, "PHY DEBUG_R0=0x%08x DEBUG_R1=0x%08x\n",
+	       readl(sv->ctrl.iobase + PHY_DEBUG_R0),
+	       readl(sv->ctrl.iobase + PHY_DEBUG_R1));
+}
+
+static int pcie_sifive_set_check_atu(struct pcie_sifive *sv, u32 region)
+{
+	u32 retries, val;
+
+	/*
+	 * Make sure ATU enable takes effect before any subsequent config
+	 * and I/O accesses.
+	 */
+	for (retries = 0; retries < ATU_WAIT_MAX_RETRIES; retries++) {
+		val = readl(sv->ctrl.iobase + region + ATU_REGION_CTRL2);
+		if (val & ATU_ENABLE)
+			return 0;
+
+		mdelay(ATU_WAIT);
+	}
+
+	return -EBUSY;
+}
+
+static void pcie_sifive_set_atu(struct pcie_sifive *sv, u32 region,
+				u32 ctrl1, u32 ctrl2, u64 size,
+				u64 base_addr, u64 target_addr)
+{
+	u64 limit_addr = base_addr + size - 1;
+
+	if (upper_32_bits(size))
+		ctrl1 |= ATU_INCREASE_REGION_SIZE;
+
+	writel(lower_32_bits(base_addr),
+	       sv->ctrl.iobase + region + ATU_LOWER_BASE);
+	writel(upper_32_bits(base_addr),
+	       sv->ctrl.iobase + region + ATU_UPPER_BASE);
+	writel(lower_32_bits(limit_addr),
+	       sv->ctrl.iobase + region + ATU_LOWER_LIMIT);
+	writel(upper_32_bits(limit_addr),
+	       sv->ctrl.iobase + region + ATU_UPPER_LIMIT);
+	writel(lower_32_bits(target_addr),
+	       sv->ctrl.iobase + region + ATU_LOWER_TARGET);
+	writel(upper_32_bits(target_addr),
+	       sv->ctrl.iobase + region + ATU_UPPER_TARGET);
+	writel(ctrl1, sv->ctrl.iobase + region + ATU_REGION_CTRL1);
+	writel(ctrl2 | ATU_ENABLE, sv->ctrl.iobase + region + ATU_REGION_CTRL2);
+}
+
+static void pcie_sifive_set_outbound_atu(struct pcie_sifive *sv,
+					 u32 index, u32 ctrl1, u32 ctrl2,
+					 u64 size, u64 cpu_addr, u64 pci_addr)
+{
+	u32 region = ATU_CONFIG(ATU_OUTBOUND_REGION(index));
+
+	pcie_sifive_set_atu(sv, region, ctrl1, ctrl2, size, cpu_addr, pci_addr);
+
+	if (pcie_sifive_set_check_atu(sv, region))
+		sv_err(sv, "Outbound ATU could not be enabled\n");
+}
+
+static void __iomem *pcie_sifive_cfg_outbound_atu(struct pcie_sifive *sv,
+						  u32 bdf, u32 where)
+{
+	u32 bus, ctrl1;
+
+	where &= ~0x3;
+
+	bus = ((bdf >> 16) & 0xff) - sv->pci.pp.root_bus_nr;
+	if (!bus)
+		return sv->ctrl.iobase + PCI_CONFIG(where);
+
+	if (bus == 1)
+		ctrl1 = ATU_TYPE_CFG0;
+	else
+		ctrl1 = ATU_TYPE_CFG1;
+
+	bdf = (bus << 16) | (bdf & 0xffff);
+	pcie_sifive_set_outbound_atu(sv, 1, ctrl1, 0, SZ_4K,
+				     sv->pci.pp.cfg1_base,
+				     (u64)(bdf << 8));
+
+	return sv->pci.pp.va_cfg1_base + where;
+}
+
+static void pcie_sifive_set_outbound_mem_atu(struct pcie_sifive *sv, u32 index,
+					     u64 size, u64 cpu_addr,
+					     u64 pci_addr)
+{
+	pcie_sifive_set_outbound_atu(sv, index, ATU_TYPE_MEM, 0,
+				     size, cpu_addr, pci_addr);
+}
+
+static void pcie_sifive_set_outbound_io_atu(struct pcie_sifive *sv, u32 index,
+					    u64 size, u64 cpu_addr,
+					    u64 pci_addr)
+{
+	pcie_sifive_set_outbound_atu(sv, index, ATU_TYPE_IO, 0,
+				     size, cpu_addr, pci_addr);
+}
+
+static int pcie_sifive_set_outbound_ecam_atu(struct pcie_sifive *sv, u32 index,
+					     u64 cpu_addr)
+{
+	pcie_sifive_set_outbound_atu(sv, index++,
+				     ATU_TYPE_CFG0, ATU_CFG_SHIFT_MODE,
+				     SZ_4K, cpu_addr, 0);
+
+	pcie_sifive_set_outbound_atu(sv, index++,
+				     ATU_TYPE_CFG1, ATU_CFG_SHIFT_MODE,
+				     SZ_256M - SZ_1M,
+				     cpu_addr + SZ_1M,
+				     SZ_1M);
+	return index;
+}
+
+static void pcie_sifive_assert_phy_reset(struct pcie_sifive *sv)
+{
+	writel(0x1, sv->priv.iobase + PCIEX8MGMT_APP_HOLD_PHY_RST);
+}
+
+static int pcie_sifive_wait_for_link(struct pcie_sifive *sv)
+{
+	u32 val;
+	int timeout;
+
+	/* Wait for the link to train */
+	mdelay(20);
+	timeout = 20;
+
+	do {
+		mdelay(1);
+	} while (--timeout && !pcie_sifive_check_link(sv));
+
+	val = readl(sv->ctrl.iobase + PHY_DEBUG_R1);
+	if (!(val & PHY_DEBUG_R1_LINK_UP) ||
+	    (val & PHY_DEBUG_R1_LINK_IN_TRAINING)) {
+		sv_info(sv, "Failed to negotiate PCIe link!\n");
+		pcie_sifive_print_phy_debug(sv);
+		pcie_sifive_assert_phy_reset(sv);
+		return -ETIMEDOUT;
+	}
+
+	sv_info(sv, "PCIe Link up, Gen%i\n",
+		readw(sv->ctrl.iobase + PF0_PCIE_CAP_LINK_STATUS) &
+		PCIE_LINK_STATUS_SPEED_MASK);
+
+	return 0;
+}
+
+static void pcie_sifive_setup_link(struct pcie_sifive *sv)
+{
+	u32 lanes;
+
+	lanes = pcie_sifive_get_required_property(sv, "num-lanes");
+	if (lanes > 0) {
+		pcie_sifive_set_link_num_lanes(sv, lanes);
+		pcie_sifive_set_link_width(sv, lanes);
+	}
+}
+
+static int pcie_sifive_start_link(struct pcie_sifive *sv)
+{
+	if (pcie_sifive_check_link(sv))
+		return -EALREADY;
+
+	pcie_sifive_force_gen1(sv);
+
+	/* set ltssm */
+	pcie_sifive_priv_set_state(sv, MGMT_MISC_LTSSM_ENABLE_OFFSET,
+				   MGMT_MISC_LTSSM_ENABLE_BIT, 1);
+	return 0;
+}
+
+static void pcie_sifive_setup_host_atu(struct pcie_sifive *sv)
+{
+	pcie_sifive_set_outbound_mem_atu(sv, 0,
+					 sv->pci.pp.mem_size,
+					 sv->pci.pp.mem_base,
+					 sv->pci.pp.mem_bus_addr);
+
+	if (sv->pci.num_viewport > 2)
+		pcie_sifive_set_outbound_io_atu(sv, 2,
+						sv->pci.pp.io_size,
+						sv->pci.pp.io_base,
+						sv->pci.pp.io_bus_addr);
+
+	if (sv->pci.pp.ecam.iobase)
+		pcie_sifive_set_outbound_ecam_atu(sv, 3,
+						  (u64)sv->pci.pp.ecam.iobase);
+}
+
+static void pcie_sifive_setup_host_prefetch(struct pcie_sifive *sv)
+{
+	u32 val;
+
+	/* ctrl_ro_wr_enable */
+	val = readl(sv->ctrl.iobase + PCIE_MISC_CONTROL_1);
+	val |= DBI_RO_WR_EN;
+	writel(val, sv->ctrl.iobase + PCIE_MISC_CONTROL_1);
+
+	writew(0xf, sv->ctrl.iobase + PCI_CONFIG(PCI_PREF_MEMORY_BASE));
+	writew(0xf, sv->ctrl.iobase + PCI_CONFIG(PCI_PREF_MEMORY_LIMIT));
+	writel(0x20, sv->ctrl.iobase + PCI_CONFIG(PCI_PREF_BASE_UPPER32));
+	writel(0x40, sv->ctrl.iobase + PCI_CONFIG(PCI_PREF_LIMIT_UPPER32));
+
+	/* ctrl_ro_wr_disable */
+	val &= ~DBI_RO_WR_EN;
+	writel(val, sv->ctrl.iobase + PCIE_MISC_CONTROL_1);
+}
+
+static void pcie_sifive_setup_host(struct pcie_sifive *sv)
+{
+	u32 val;
+
+	sv->pci.iatu_unroll_enabled = true;
+
+	pcie_sifive_setup_link(sv);
+
+	/* ctrl_ro_wr_enable */
+	val = readl(sv->ctrl.iobase + PCIE_MISC_CONTROL_1);
+	val |= DBI_RO_WR_EN;
+	writel(val, sv->ctrl.iobase + PCIE_MISC_CONTROL_1);
+
+	/* Setup correct class code for host bridge */
+	writew(PCI_CLASS_BRIDGE_PCI,
+	       sv->ctrl.iobase + PCI_CONFIG(PCI_CLASS_DEVICE));
+
+	/* ctrl_ro_wr_disable */
+	val &= ~DBI_RO_WR_EN;
+	writel(val, sv->ctrl.iobase + PCIE_MISC_CONTROL_1);
+
+	writeb(PCI_HEADER_TYPE_BRIDGE,
+	       sv->ctrl.iobase + PCI_CONFIG(PCI_HEADER_TYPE));
+
+	/* Setup RC BARs */
+	writel(0x4, sv->ctrl.iobase + PCI_CONFIG(PCI_BASE_ADDRESS_0));
+	writel(0x0, sv->ctrl.iobase + PCI_CONFIG(PCI_BASE_ADDRESS_1));
+
+	pcie_sifive_set_pci_int_pin(sv, PCI_INTERRUPT_INTA);
+
+	/* Setup bus numbers */
+	val = readl(sv->ctrl.iobase + PCI_CONFIG(PCI_PRIMARY_BUS)) &
+	      ~0x00ffffff;
+	val |= 0x00ff0100;
+	writel(val, sv->ctrl.iobase + PCI_CONFIG(PCI_PRIMARY_BUS));
+
+	/* Setup command register */
+	writew(PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER |
+	       PCI_COMMAND_SERR, sv->ctrl.iobase + PCI_CONFIG(PCI_COMMAND));
+
+	pcie_sifive_setup_host_atu(sv);
+
+	writel(0x0, sv->ctrl.iobase + PCI_CONFIG(PCI_BASE_ADDRESS_0));
+
+	pcie_sifive_setup_host_prefetch(sv);
+}
+
+static int pcie_sifive_init_host(struct pcie_sifive *sv)
+{
+	pcie_sifive_setup_host(sv);
+
+	if (pcie_sifive_start_link(sv) == -EALREADY)
+		sv_info(sv, "PCIe link is already up\n");
+	else if (pcie_sifive_wait_for_link(sv) == -ETIMEDOUT)
+		return -ETIMEDOUT;
+
+	return 0;
+}
+
+static int pcie_sifive_addr_valid(struct pcie_sifive *sv, pci_dev_t bdf)
+{
+	if ((PCI_BUS(bdf) == sv->pci.pp.root_bus_nr) && (PCI_DEV(bdf) > 0))
+		return 0;
+	if ((PCI_BUS(bdf) == sv->pci.pp.root_bus_nr + 1) && (PCI_DEV(bdf) > 0))
+		return 0;
+
+	return 1;
+}
+
+static int pcie_sifive_read_config(const struct udevice *bus, pci_dev_t bdf,
+				   uint offset, ulong *valuep,
+				   enum pci_size_t size)
+{
+	struct pcie_sifive *sv = dev_get_priv(bus);
+	void __iomem *va;
+	ulong value;
+
+	sv_debug(sv, "PCIe CFG read:  (b,d,f)=(%2d,%2d,%2d) ",
+		 PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf));
+
+	if (!pcie_sifive_addr_valid(sv, bdf)) {
+		sv_debug(sv, "- out of range\n");
+		*valuep = pci_get_ff(size);
+		return 0;
+	}
+
+	va = pcie_sifive_cfg_outbound_atu(sv, bdf, offset);
+	value = readl(va);
+
+	sv_debug(sv, "(addr,val)=(0x%04x, 0x%08lx)\n", offset, value);
+	*valuep = pci_conv_32_to_size(value, offset, size);
+
+	if (sv->pci.num_viewport <= 2)
+		pcie_sifive_set_outbound_io_atu(sv, 1,
+						sv->pci.pp.io_size,
+						sv->pci.pp.io_base,
+						sv->pci.pp.io_bus_addr);
+	return 0;
+}
+
+static int pcie_sifive_write_config(struct udevice *bus, pci_dev_t bdf,
+				    uint offset, ulong value,
+				    enum pci_size_t size)
+{
+	struct pcie_sifive *sv = dev_get_priv(bus);
+	void __iomem *va;
+	ulong old;
+
+	sv_debug(sv, "PCIe CFG write: (b,d,f)=(%2d,%2d,%2d) ",
+		 PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf));
+	sv_debug(sv, "(addr,val)=(0x%04x, 0x%08lx)\n", offset, value);
+
+	if (!pcie_sifive_addr_valid(sv, bdf)) {
+		sv_debug(sv, "- out of range\n");
+		return 0;
+	}
+
+	va = pcie_sifive_cfg_outbound_atu(sv, bdf, offset);
+	old = readl(va);
+	value = pci_conv_size_to_32(old, value, offset, size);
+	writel(value, va);
+
+	if (sv->pci.num_viewport <= 2)
+		pcie_sifive_set_outbound_io_atu(sv, 1,
+						sv->pci.pp.io_size,
+						sv->pci.pp.io_base,
+						sv->pci.pp.io_bus_addr);
+	return 0;
+}
+
+bool pcie_sifive_set_mode(struct pcie_sifive *sv, enum pcie_sifive_devtype mode)
+{
+	int ret;
+
+	pcie_sifive_assert_perstn(sv);
+	pcie_sifive_power_on(sv);
+	pcie_sifive_deassert_perstn(sv);
+
+	clk_enable(&sv->aux_ck);
+
+	/*
+	 * assert hold_phy_rst (hold the controller LTSSM in reset
+	 * after power_up_rst_n for register programming with cr_para)
+	 */
+	pcie_sifive_assert_phy_reset(sv);
+
+	/* deassert power_up_rst_n */
+	ret = reset_deassert(&sv->reset);
+	if (ret < 0) {
+		pr_err("reset_assert() failed: %d", ret);
+		return false;
+	}
+
+	pcie_sifive_init_phy(sv);
+
+	clk_disable(&sv->aux_ck);
+
+	/* deassert phy reset */
+	writel(0x0, sv->priv.iobase + PCIEX8MGMT_APP_HOLD_PHY_RST);
+
+	/* enable pcieauxclk */
+	clk_enable(&sv->aux_ck);
+
+	/* Set desired mode while core is not operational */
+	if (mode == SV_PCIE_HOST_TYPE)
+		writel(MGMT_MISC_DEVICE_TYPE_RC,
+		       sv->priv.iobase + MGMT_MISC_DEVICE_TYPE_OFFSET);
+	else
+		writel(MGMT_MISC_DEVICE_TYPE_EP,
+		       sv->priv.iobase + MGMT_MISC_DEVICE_TYPE_OFFSET);
+
+	/* Confirm desired mode from operational core */
+	if (pcie_sifive_get_devtype(sv) != mode)
+		return false;
+
+	sv->mode = mode;
+
+	return true;
+}
+
+static int pcie_sifive_probe(struct udevice *dev)
+{
+	struct pcie_sifive *sv = dev_get_priv(dev);
+	struct udevice *parent = pci_get_controller(dev);
+	struct pci_controller *hose = dev_get_uclass_priv(parent);
+	int err;
+
+	sv->ctrl.iobase = (void __iomem *)sv->ctrl.phys_base;
+	sv->priv.iobase = (void __iomem *)sv->priv.phys_base;
+
+	sv->pci.dev = dev;
+	sv->pci.pp.root_bus_nr = dev_seq(dev);
+
+	sv->pci.pp.io_size = hose->regions[0].size;
+	sv->pci.pp.io_base = hose->regions[0].phys_start;
+	sv->pci.pp.io_bus_addr = hose->regions[0].bus_start;
+
+	sv->pci.pp.mem_size = hose->regions[1].size;
+	sv->pci.pp.mem_base = hose->regions[1].phys_start;
+	sv->pci.pp.mem_bus_addr = hose->regions[1].bus_start;
+
+	sv->pci.pp.config.iobase = (void __iomem *)sv->pci.pp.config.phys_base;
+	sv->pci.pp.ecam.iobase = (void __iomem *)sv->pci.pp.ecam.phys_base;
+
+	sv->pci.pp.cfg0_base = sv->pci.pp.config.phys_base;
+	sv->pci.pp.va_cfg0_base = (void __iomem *)sv->pci.pp.cfg0_base;
+	sv->pci.pp.cfg0_size = SZ_4K;
+
+	sv->pci.pp.cfg1_base = sv->pci.pp.cfg0_base + sv->pci.pp.cfg0_size;
+	sv->pci.pp.va_cfg1_base = (void __iomem *)sv->pci.pp.cfg1_base;
+	sv->pci.pp.cfg1_size = SZ_4K;
+
+	sv->pci.pp.msi_data = sv->pci.pp.cfg1_base + sv->pci.pp.cfg1_size;
+
+	gpio_request_by_name(dev, "pwren-gpios", 0, &sv->pwren_gpio,
+			     GPIOD_IS_OUT);
+
+	if (!dm_gpio_is_valid(&sv->pwren_gpio)) {
+		sv_info(sv, "pwren_gpio is invalid\n");
+		return -EINVAL;
+	}
+
+	gpio_request_by_name(dev, "perstn-gpios", 0, &sv->perstn_gpio,
+			     GPIOD_IS_OUT);
+
+	if (!dm_gpio_is_valid(&sv->perstn_gpio)) {
+		sv_info(sv, "perstn_gpio is invalid\n");
+		return -EINVAL;
+	}
+
+	err = clk_get_by_index(dev, 0, &sv->aux_ck);
+	if (err) {
+		sv_info(sv, "clk_get_by_index(aux_ck) failed: %d\n", err);
+		return err;
+	}
+
+	err = reset_get_by_index(dev, 0, &sv->reset);
+	if (err) {
+		sv_info(sv, "reset_get_by_index(reset) failed: %d\n", err);
+		return err;
+	}
+
+	if (!pcie_sifive_set_mode(sv, SV_PCIE_HOST_TYPE)) {
+		sv_info(sv, "Unable to set desired PCIe operation mode\n");
+		return -EINVAL;
+	}
+
+	return pcie_sifive_init_host(sv);
+}
+
+static int pcie_sifive_of_to_plat(struct udevice *dev)
+{
+	struct pcie_sifive *sv = dev_get_priv(dev);
+
+	sv->pci.dev = dev;
+
+	sv->ctrl.phys_base = dev_read_addr_size_name(dev, "dbi",
+						     &sv->ctrl.iosize);
+	if (sv->ctrl.phys_base == FDT_ADDR_T_NONE)
+		return -EINVAL;
+
+	sv->priv.phys_base = dev_read_addr_size_name(dev, "mgmt",
+						     &sv->priv.iosize);
+	if (sv->priv.phys_base == FDT_ADDR_T_NONE)
+		return -EINVAL;
+
+	sv->pci.pp.config.phys_base =
+		dev_read_addr_size_name(dev, "config",
+					&sv->pci.pp.config.iosize);
+	if (sv->pci.pp.config.phys_base == FDT_ADDR_T_NONE)
+		return -EINVAL;
+
+	sv->pci.pp.ecam.phys_base =
+		dev_read_addr_size_name(dev, "ecam", &sv->pci.pp.ecam.iosize);
+	if (sv->pci.pp.config.phys_base == FDT_ADDR_T_NONE)
+		sv->pci.pp.ecam.phys_base = 0;
+
+	sv->pci.num_viewport = pcie_sifive_get_property(sv, "num-viewport");
+	if (sv->pci.num_viewport == 0)
+		sv->pci.num_viewport = 2;
+
+	return 0;
+}
+
+static const struct dm_pci_ops pcie_sifive_ops = {
+	.read_config	= pcie_sifive_read_config,
+	.write_config	= pcie_sifive_write_config
+};
+
+static const struct udevice_id pcie_sifive_ids[] = {
+	{ .compatible = "sifive,fu740-pcie" },
+	{ .compatible = "sifive,fu740-pcie-ecam" },
+	{}
+};
+
+U_BOOT_DRIVER(pcie_sifive) = {
+	.name		= "pcie_sifive",
+	.id		= UCLASS_PCI,
+	.of_match	= pcie_sifive_ids,
+	.ops		= &pcie_sifive_ops,
+	.of_to_plat	= pcie_sifive_of_to_plat,
+	.probe		= pcie_sifive_probe,
+	.priv_auto	= sizeof(struct pcie_sifive),
+};
diff --git a/drivers/pci/pcie_sifive.h b/drivers/pci/pcie_sifive.h
new file mode 100644
index 0000000000..d12c1f715e
--- /dev/null
+++ b/drivers/pci/pcie_sifive.h
@@ -0,0 +1,374 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * SiFive FU740 DesignWare PCIe Controller
+ *
+ * Copyright (C) 2020-2021 SiFive, Inc.
+ *
+ * Based in early part on the i.MX6 PCIe host controller shim which is:
+ *
+ * Copyright (C) 2013 Kosagi
+ *		http://www.kosagi.com
+ *
+ * Based on driver from author: Alan Mikhak <amikhak@wirelessfabric.com>
+ */
+
+#ifndef __PCIE_SIFIVE_H__
+#define __PCIE_SIFIVE_H__
+
+#include <clk.h>
+#include <pci.h>
+#include <asm/io.h>
+#include <linux/bitops.h>
+#include <linux/log2.h>
+#include <pci_ep.h>
+#include <pci_ids.h>
+#include <generic-phy.h>
+#include <regmap.h>
+#include <reset.h>
+#include <syscon.h>
+#include <asm-generic/gpio.h>
+
+#define MAX_MSI_IRQS		256
+#define MAX_MSI_IRQS_PER_CTRL	32
+#define MAX_MSI_CTRLS		(MAX_MSI_IRQS / MAX_MSI_IRQS_PER_CTRL)
+
+enum pcie_sifive_devtype {
+	SV_PCIE_UNKNOWN_TYPE = 0,
+	SV_PCIE_ENDPOINT_TYPE = 1,
+	SV_PCIE_HOST_TYPE = 3
+};
+
+struct sv_iomem {
+	fdt_size_t iosize;
+	void __iomem *iobase;
+	fdt_addr_t phys_base;
+};
+
+struct pcie_sifive {
+	struct {
+		struct udevice *dev;
+		u32 num_viewport;
+		u8 iatu_unroll_enabled;
+		struct {
+			u8 root_bus_nr;
+			u64 cfg0_base;
+			void __iomem *va_cfg0_base;
+			fdt_size_t cfg0_size;
+			u64 cfg1_base;
+			void __iomem *va_cfg1_base;
+			fdt_size_t cfg1_size;
+			u32 io_size;
+			u64 io_base;
+			u64 io_bus_addr;
+			u64 mem_size;
+			u64 mem_base;
+			u64 mem_bus_addr;
+			u64 msi_data;
+			u32 num_vectors;
+			u32 irq_mask[MAX_MSI_CTRLS];
+			struct sv_iomem config;
+			struct sv_iomem ecam;
+		} pp;
+	} pci;
+	struct sv_iomem ctrl;
+	struct sv_iomem priv;
+	enum pcie_sifive_devtype mode;
+	int sys_int_pin;
+	struct gpio_desc pwren_gpio;
+	struct gpio_desc perstn_gpio;
+	struct clk aux_ck;
+	struct reset_ctl reset;
+};
+
+#define sv_info(sv, fmt, arg...)	printf(fmt, ## arg)
+#define sv_warn(sv, fmt, arg...)	printf(fmt, ## arg)
+#define sv_debug(sv, fmt, arg...)	debug(fmt, ## arg)
+#define sv_err(sv, fmt, arg...)		printf(fmt, ## arg)
+
+#define pci_epf_header pci_ep_header
+
+#define VENDOR_ID_MASK	GENMASK(15, 0)
+#define DEVICE_ID_SHIFT	16
+
+#ifndef PCI_MSIX_FLAGS
+#define PCI_MSIX_FLAGS		2       /* Message Control */
+#define  PCI_MSIX_FLAGS_QSIZE		0x07FF  /* Table size */
+#define  PCI_MSIX_FLAGS_MASKALL		0x4000  /* Mask all vectors */
+#define  PCI_MSIX_FLAGS_ENABLE		0x8000  /* MSI-X enable */
+#endif
+
+#ifndef PCI_REBAR_CAP
+#define PCI_REBAR_CAP		4       /* capability register */
+#define  PCI_REBAR_CAP_SIZES		0x00FFFFF0  /* supported BAR sizes */
+#endif
+
+#ifndef PCI_REBAR_CTRL
+#define PCI_REBAR_CTRL		8       /* control register */
+#define  PCI_REBAR_CTRL_BAR_IDX		0x00000007  /* BAR index */
+#define  PCI_REBAR_CTRL_NBAR_MASK	0x000000E0  /* # of resizable BARs */
+#define  PCI_REBAR_CTRL_NBAR_SHIFT	5           /* shift for # of BARs */
+#define  PCI_REBAR_CTRL_BAR_SIZE	0x00001F00  /* BAR size */
+#define  PCI_REBAR_CTRL_BAR_SHIFT	8           /* shift for BAR size */
+#endif
+
+#define MGMT_MISC_LTSSM_ENABLE_OFFSET	0x10
+#define MGMT_MISC_SYS_INT_OFFSET	0x238
+#define MGMT_MISC_EDMA_XFER_PEND_OFFSET	0x4d0
+#define MGMT_MISC_EDMA_INT_OFFSET	0x630
+#define MGMT_MISC_DEVICE_TYPE_OFFSET	0x708
+
+#define MGMT_MISC_LTSSM_ENABLE_BIT	BIT(0)
+#define MGMT_MISC_EDMA_XFER_PEND_BIT	BIT(0)
+#define MGMT_MISC_EDMA_INT_BITS		(BIT(1) | BIT(0))
+
+#define MGMT_MISC_DEVICE_TYPE_EP	0x0
+#define MGMT_MISC_DEVICE_TYPE_RC	0x4
+
+/* Doorbell Interface */
+#define DBI_OFFSET			0x0
+#define DBI_SIZE			0x1000
+
+/* Doorbell Interface 2 */
+#define DBI2_OFFSET			0x100000
+#define DBI2_SIZE			0x80
+
+/* Address Translation Units */
+#define ATU_OFFSET			0x300000
+#define ATU_SIZE			0x80000
+
+/* DMA Engines */
+#define DMA_OFFSET			0x380000
+#define DMA_SIZE			0x80000
+
+#define DMA_WRITE_ENGINE_EN_OFFSET	0x0C
+
+#define DMA_WRITE_DOORBELL_OFFSET	0x10
+
+#define DMA_READ_ENGINE_EN_OFFSET	0x2C
+
+#define DMA_READ_DOORBELL_OFFSET	0x30
+
+#define DMA_WRITE_INT_STATUS_OFFSET	0x4C
+#define DMA_WRITE_INT_MASK_OFFSET	0x54
+#define DMA_WRITE_INT_CLEAR_OFFSET	0x58
+
+#define DMA_READ_INT_STATUS_OFFSET	0xA0
+#define DMA_READ_INT_MASK_OFFSET	0xA8
+#define DMA_READ_INT_CLEAR_OFFSET	0xAC
+
+#define DMA_WRITE_LL_ERR_EN_OFFSET	0x90
+
+#define DMA_READ_LL_ERR_EN_OFFSET	0xC4
+
+#define DMA_WRITE_CONTROL1_OFFSET	0x200
+#define DMA_WRITE_TRANSFER_SIZE_OFFSET	0x208
+#define DMA_WRITE_SAR_LOW_OFFSET	0x20C
+#define DMA_WRITE_SAR_HI_OFFSET		0x210
+#define DMA_WRITE_DAR_LOW_OFFSET	0x214
+#define DMA_WRITE_DAR_HI_OFFSET		0x218
+
+#define DMA_READ_CONTROL1_OFFSET	0x300
+#define DMA_READ_TRANSFER_SIZE_OFFSET	0x308
+#define DMA_READ_SAR_LOW_OFFSET		0x30C
+#define DMA_READ_SAR_HI_OFFSET		0x310
+#define DMA_READ_DAR_LOW_OFFSET		0x314
+#define DMA_READ_DAR_HI_OFFSET		0x318
+
+#define DMA_CHAN_BIT(chan)		(BIT(chan))
+#define DMA_ENABLE_BIT_CHAN(chan)	DMA_CHAN_BIT(chan)
+#define DMA_LLLAIE_BIT_CHAN(chan)	DMA_CHAN_BIT(chan)
+#define DMA_INT_DONE_BIT_CHAN(chan)	DMA_CHAN_BIT(chan)
+#define DMA_INT_ABORT_BIT_CHAN(chan)	(BIT((chan) + 16))
+
+/* PCIe Port Logic registers (memory-mapped) */
+#define PL_OFFSET			0x700
+#define PCIE_PL_PFLR			(PL_OFFSET + 0x08)
+#define PCIE_PL_PFLR_LINK_STATE		(0x3f << 16)
+#define PCIE_PL_PFLR_FORCE_LINK		BIT(15)
+
+#define LINK_CONTROL			(PL_OFFSET + 0x10)
+#define LINK_MODE(n)			((n) << 16)
+#define LINK_MODE_MASK			LINK_MODE(0x3f)
+#define LINK_MODE_1_LANE		LINK_MODE(0x1)
+#define LINK_MODE_2_LANES		LINK_MODE(0x3)
+#define LINK_MODE_4_LANES		LINK_MODE(0x7)
+#define LINK_MODE_8_LANES		LINK_MODE(0xf)
+
+#define PHY_DEBUG_R0			(PL_OFFSET + 0x28)
+
+#define PHY_DEBUG_R1			(PL_OFFSET + 0x2c)
+#define PHY_DEBUG_R1_LINK_UP		(0x1 << 4)
+#define PHY_DEBUG_R1_LINK_IN_TRAINING	(0x1 << 29)
+
+#define LINK_WIDTH_SPEED_CONTROL	(PL_OFFSET + 0x10c)
+#define LINK_WIDTH(n)			((n) << 8)
+#define LINK_WIDTH_MASK			LINK_WIDTH(0x1f)
+#define LINK_WIDTH_1_LANE		LINK_WIDTH(0x1)
+#define LINK_WIDTH_2_LANES		LINK_WIDTH(0x2)
+#define LINK_WIDTH_4_LANES		LINK_WIDTH(0x4)
+#define LINK_WIDTH_8_LANES		LINK_WIDTH(0x8)
+
+#define PHY_STAT			(PL_OFFSET + 0x110)
+#define PHY_STAT_ACK_LOC		16
+
+#define PHY_CTRL			(PL_OFFSET + 0x114)
+#define PHY_CTRL_DATA_LOC		0
+#define PHY_CTRL_CAP_ADR_LOC		16
+#define PHY_CTRL_CAP_DAT_LOC		17
+#define PHY_CTRL_WR_LOC			18
+#define PHY_CTRL_RD_LOC			19
+
+#define MSI_CTRL_BLOCK_SIZE		12
+#define MSI_CTRL_BLOCK(ctrl)		((ctrl) * MSI_CTRL_BLOCK_SIZE)
+#define MSI_CTRL_INT_ENABLE(ctrl)	(0x828 + MSI_CTRL_BLOCK(ctrl))
+#define MSI_CTRL_INT_MASK(ctrl)		(0x82c + MSI_CTRL_BLOCK(ctrl))
+#define MSI_CTRL_INT_STATUS(ctrl)	(0x830 + MSI_CTRL_BLOCK(ctrl))
+
+#define PCIE_MISC_CONTROL_1		0x8bc
+#define DBI_RO_WR_EN			BIT(0)
+
+#define ATU_VIEWPORT			0x900
+#define ATU_REGION_MIN_SIZE		BIT(16)
+#define ATU_REGION_INBOUND		BIT(31)
+#define ATU_REGION_OUTBOUND		0
+
+#define ATU_VIEWPORT_CTRL_1		0x904
+#define ATU_TYPE_MASK			0xf
+#define ATU_TYPE_MEM			0x0
+#define ATU_TYPE_IO			0x2
+#define ATU_TYPE_CFG0			0x4
+#define ATU_TYPE_CFG1			0x5
+#ifdef CONFIG_PCI_ALMOND_FPGA_REV8
+#define ATU_INCREASE_REGION_SIZE	0
+#else
+#define ATU_INCREASE_REGION_SIZE	BIT(13)
+#endif
+
+#define ATU_VIEWPORT_CTRL_2		0x908
+#define ATU_CFG_SHIFT_MODE		BIT(28)
+#define ATU_BAR_MATCH_MODE		BIT(30)
+#define ATU_ENABLE			BIT(31)
+#define ATU_DISABLE			(u32)~ATU_ENABLE
+
+#define ATU_MAX_IN			16
+#define ATU_MAX_OUT			16
+
+#define ATU_WAIT_MAX_RETRIES		5
+#define ATU_WAIT			9
+
+/*
+ * iATU Unroll-specific register definitions
+ * From 4.80 core version the address translation will be made by unroll
+ */
+#define ATU_REGION_CTRL1		0x00
+#define ATU_REGION_CTRL2		0x04
+#define ATU_LOWER_BASE			0x08
+#define ATU_UPPER_BASE			0x0C
+#define ATU_LOWER_LIMIT			0x10
+#define ATU_LOWER_TARGET		0x14
+#define ATU_UPPER_TARGET		0x18
+#define ATU_UPPER_LIMIT			0x20
+
+#define ATU_OUTBOUND_REGION(region)	((region) << 9)
+#define ATU_INBOUND_REGION(region)	(((region) << 9) | BIT(8))
+
+#define SIFIVE_PCIEAUXGATECFG 0x14
+#define SIFIVE_DEVICESRESETREG 0x28
+
+#define PCIEX8MGMT_PERST_N 0x0
+#define PCIEX8MGMT_APP_LTSSM_ENABLE	0x10
+#define PCIEX8MGMT_APP_HOLD_PHY_RST 0x18
+#define PCIEX8MGMT_DEVICE_TYPE		0x708
+#define PCIEX8MGMT_PHY0_CR_PARA_ADDR 0x860
+#define PCIEX8MGMT_PHY0_CR_PARA_RD_EN 0x870
+#define PCIEX8MGMT_PHY0_CR_PARA_RD_DATA 0x878
+#define PCIEX8MGMT_PHY0_CR_PARA_SEL 0x880
+#define PCIEX8MGMT_PHY0_CR_PARA_WR_DATA 0x888
+#define PCIEX8MGMT_PHY0_CR_PARA_WR_EN 0x890
+#define PCIEX8MGMT_PHY0_CR_PARA_ACK 0x898
+#define PCIEX8MGMT_PHY1_CR_PARA_ADDR 0x8a0
+#define PCIEX8MGMT_PHY1_CR_PARA_RD_EN 0x8b0
+#define PCIEX8MGMT_PHY1_CR_PARA_RD_DATA 0x8b8
+#define PCIEX8MGMT_PHY1_CR_PARA_SEL 0x8c0
+#define PCIEX8MGMT_PHY1_CR_PARA_WR_DATA 0x8c8
+#define PCIEX8MGMT_PHY1_CR_PARA_WR_EN 0x8d0
+#define PCIEX8MGMT_PHY1_CR_PARA_ACK 0x8d8
+
+#define PCIEX8MGMT_LANE_NUM 8
+#define PCIEX8MGMT_LANE 0x1008
+#define PCIEX8MGMT_LANE_OFF 0x100
+#define PCIEX8MGMT_TERM_MODE 0x0e21
+
+/* PCIe Port Logic registers (memory-mapped) */
+#define PL_OFFSET 0x700
+#define PCIE_PL_PFLR (PL_OFFSET + 0x08)
+#define PCIE_PL_PFLR_LINK_STATE_MASK		(0x3f << 16)
+#define PCIE_PL_PFLR_FORCE_LINK			BIT(15)
+#define PCIE_PHY_DEBUG_R0 (PL_OFFSET + 0x28)
+#define PCIE_PHY_DEBUG_R1 (PL_OFFSET + 0x2c)
+#define PCIE_PL_GEN2_CTRL_OFF (PL_OFFSET + 0x10c)
+#define PCIE_PL_DIRECTED_SPEED_CHANGE_OFF 0x20000
+
+#define PCIE_PHY_CTRL (PL_OFFSET + 0x114)
+#define PCIE_PHY_CTRL_DATA_LOC 0
+#define PCIE_PHY_CTRL_CAP_ADR_LOC 16
+#define PCIE_PHY_CTRL_CAP_DAT_LOC 17
+#define PCIE_PHY_CTRL_WR_LOC 18
+#define PCIE_PHY_CTRL_RD_LOC 19
+
+#define PCIE_PHY_STAT (PL_OFFSET + 0x110)
+#define PCIE_PHY_STAT_ACK_LOC 16
+
+#define PCIE_LINK_WIDTH_SPEED_CONTROL	0x80C
+
+/* PCIe Root Complex registers (memory-mapped) */
+#define PCIE_RC_PF0_MSI_CAP			0x50
+#define PCI_MSI_CAP_ID_NEXT_CTRL_REG		(PCIE_RC_PF0_MSI_CAP + 0x0)
+
+#define PCIE_RC_PF0_MSIX_CAP			0x0
+
+#define PCIE_DSP_PF0_PCIE_CAP_BASE		0x70
+#define PCIE_RC_LCR				(PCIE_DSP_PF0_PCIE_CAP_BASE + 0xc)
+#define PCIE_RC_LCR_MAX_LINK_SPEEDS_GEN1	0x1
+#define PCIE_RC_LCR_MAX_LINK_SPEEDS_GEN2	0x2
+#define PCIE_RC_LCR_MAX_LINK_SPEEDS_GEN3	0x3
+#define PCIE_RC_LCR_MAX_LINK_SPEEDS_MASK	0xf
+
+#define PCIE_RC_LCSR				(PCIE_DSP_PF0_PCIE_CAP_BASE + 0x10)
+
+#define DMA_CONFIG(r)			(DMA_OFFSET + (r))
+#define ATU_CONFIG(r)			(ATU_OFFSET + (r))
+#define PCI_SHADOW(r)			(DBI2_OFFSET + (r))
+#define PCI_CONFIG(r)			(DBI_OFFSET + (r))
+#define MSI_CAPABILITIES(r)		PCI_CONFIG(PCIE_RC_PF0_MSI_CAP + (r))
+#define MSIX_CAPABILITIES(r)		PCI_CONFIG(PCIE_RC_PF0_MSIX_CAP + (r))
+#define PCIE_CAPABILITIES(r)		PCI_CONFIG(PCIE_DSP_PF0_PCIE_CAP_BASE + (r))
+
+#define PF0_PCIE_CAP_LINK_CAP		PCIE_CAPABILITIES(0xc)
+#define PCIE_LINK_CAP_MAX_SPEED_MASK	0xf
+#define PCIE_LINK_CAP_MAX_SPEED_GEN1	BIT(0)
+#define PCIE_LINK_CAP_MAX_SPEED_GEN2	BIT(1)
+#define PCIE_LINK_CAP_MAX_SPEED_GEN3	BIT(2)
+#define PCIE_LINK_CAP_MAX_SPEED_GEN4	BIT(3)
+
+#define PF0_PCIE_CAP_LINK_CONTROL	PCIE_CAPABILITIES(0x10)
+
+#define PF0_PCIE_CAP_LINK_STATUS	PCIE_CAPABILITIES(0x12)
+#define PCIE_LINK_STATUS_SPEED_MASK	0xf
+
+#define PCI_CFG0_REGION_OFFSET		0x00000000
+#define PCI_CFG0_REGION_SIZE		0x00001000	/* 2^12 = 4KB */
+#define PCI_CFG1_REGION_OFFSET		0x00001000
+#define PCI_CFG1_REGION_SIZE		0x00001000	/* 2^12 = 4KB */
+#define PCI_MSI_REGION_OFFSET		0x00002000
+#define PCI_MSI_REGION_SIZE		0x00001000	/* 2^12 = 4KB */
+#define PCI_IO_REGION_OFFSET		0x00080000
+#define PCI_IO_REGION_SIZE		0x00010000	/* 2^16 = 64KB */
+#define PCI_MEM_REGION_OFFSET		0x04000000
+#define PCI_MEM_REGION_SIZE		0x04000000	/* 2^26 = 64MB */
+#define PCI_AUTOCFG_REGION_OFFSET	0x08000000
+#define PCI_AUTOCFG_REGION_SIZE		0x08000000	/* 2^27 = 128MB */
+#define PCI_ECAM_REGION_OFFSET		0x10000000
+#define PCI_ECAM_REGION_SIZE		0x10000000	/* 2^28 = 256MB */
+
+#endif /* __PCIE_SIFIVE_H__ */
