diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig
index ce861a2..7ef5b06 100644
--- a/drivers/fpga/Kconfig
+++ b/drivers/fpga/Kconfig
@@ -33,6 +33,13 @@ config FPGA_MGR_SOCFPGA_A10
 	help
 	  FPGA manager driver support for Altera Arria10 SoCFPGA.
 
+config FPGA_MGR_STRATIX_CVP
+	tristate "Altera Stratix V CvP"
+	depends on PCI
+	help
+	  FPGA manager driver support for Altera Stratix V using the
+	  CvP interface over PCIe
+
 config FPGA_MGR_ZYNQ_FPGA
 	tristate "Xilinx Zynq FPGA"
 	depends on ARCH_ZYNQ || COMPILE_TEST
diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile
index 8df07bc..0444c78 100644
--- a/drivers/fpga/Makefile
+++ b/drivers/fpga/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_FPGA)			+= fpga-mgr.o
 # FPGA Manager Drivers
 obj-$(CONFIG_FPGA_MGR_SOCFPGA)		+= socfpga.o
 obj-$(CONFIG_FPGA_MGR_SOCFPGA_A10)	+= socfpga-a10.o
+obj-$(CONFIG_FPGA_MGR_STRATIX_CVP)	+= stratix-cvp.o
 obj-$(CONFIG_FPGA_MGR_ZYNQ_FPGA)	+= zynq-fpga.o
 
 # FPGA Bridge Drivers
diff --git a/drivers/fpga/stratix-cvp.c b/drivers/fpga/stratix-cvp.c
new file mode 100644
index 0000000..5ab3499
--- /dev/null
+++ b/drivers/fpga/stratix-cvp.c
@@ -0,0 +1,529 @@
+/*
+ * Copyright (C) 2017 DENX Software Engineering
+ *
+ * Anatolij Gustschin <agust@denx.de>
+ *
+ * Manage Altera Statix V FPGA firmware using PCIe CvP.
+ * Firmware must be in binary "rbf" format.
+ */
+
+#include <linux/delay.h>
+#include <linux/fpga/fpga-mgr.h>
+#include <linux/module.h>
+#include <linux/sizes.h>
+#include <linux/pci.h>
+
+/* Vendor Specific Extended Capability Offset */
+#define VSEC_OFFSET			0x200
+#define VSEC_PCIE_EXT_CAP_ID_VAL	0x000b
+
+#define FNC		0	/* PCIe device function ID */
+#define CVP_BAR		0	/* BAR used for data transfer in memory mode */
+#define CVP_DUMMY_WR	244	/* dummy writes to clear CvP state machine */
+#define TIMEOUT_IN_US	10000
+
+/* offsets from VSEC_OFFSET */
+#define VSEC_PCIE_EXT_CAP_ID		(VSEC_OFFSET + 0x00)	/* 16bit */
+#define VSEC_VERSION			0x02		/* 8bit */
+#define VSEC_NEXT_CAP_OFF		0x03		/* 8bit */
+#define VSEC_ID				0x04		/* 16bit */
+#define VSEC_REV			0x06		/* 8bit */
+#define VSEC_LENGTH			0x07		/* 8bit */
+#define VSEC_ALTERA_MARKER		0x08		/* 32bit */
+
+#define VSEC_CVP_STATUS			(VSEC_OFFSET + 0x1e)	/* 16bit */
+#define VSEC_CVP_STATUS_DATA_ENC	(1<<0)	/* is treated as encrypted */
+#define VSEC_CVP_STATUS_DATA_COMP	(1<<1)	/* is treated as compressed */
+#define VSEC_CVP_STATUS_CFG_RDY		(1<<2)	/* CVP_CONFIG_READY */
+#define VSEC_CVP_STATUS_CFG_ERR		(1<<3)	/* CVP_CONFIG_ERROR */
+#define VSEC_CVP_STATUS_CVP_EN		(1<<4)	/* ctrl block is enabling CVP */
+#define VSEC_CVP_STATUS_USERMODE	(1<<5)	/* USERMODE */
+#define VSEC_CVP_STATUS_CFG_DONE	(1<<7)	/* CVP_CONFIG_DONE */
+#define VSEC_CVP_STATUS_PLD_CLK_IN_USE	(1<<8)	/* PLD_CLK_IN_USE */
+
+#define VSEC_CVP_MODE_CTRL		(VSEC_OFFSET + 0x20)	/* 32bit */
+#define VSEC_CVP_MODE_CTRL_CVPMODE	(1<<0) /* CVP (1) or normal mode (0) */
+#define VSEC_CVP_MODE_CTRL_HIP_CLK_SEL	(1<<1) /* PMA (1) or fabric clock (0) */
+#define VSEC_CVP_MODE_CTRL_FULL_CFG	(1<<2) /* CVP_FULLCONFIG */
+#define VSEC_CVP_MODE_CTRL_NUMCLKS	(0xff<<8) /* CVP_NUMCLKS */
+
+#define VSEC_CVP_DATA			(VSEC_OFFSET + 0x28)	/* 32bit */
+#define VSEC_CVP_PROG_CTRL		(VSEC_OFFSET + 0x2c)	/* 32bit */
+#define VSEC_CVP_PROG_CTRL_CONFIG	(1<<0)
+#define VSEC_CVP_PROG_CTRL_START_XFER	(1<<1)
+
+#define VSEC_UNCOR_ERR_STATUS		(VSEC_OFFSET + 0x34)	/* 32bit */
+#define VSEC_UNCOR_ERR_MASK		(VSEC_OFFSET + 0x38)	/* 32bit */
+#define	VSEC_UNCOR_ERR_CVP_CFG_ERR	(1<<5)	/* CVP_CONFIG_ERROR_LATCHED */
+
+#define	DRV_NAME		"stratix-cvp"
+#define	FIRMWARE_STR		"stratixv_cvp.rbf"
+#define STRATIX_V_CVP_MGR_NAME	"Stratix V CvP FPGA Manager"
+
+static char *firmware = FIRMWARE_STR;
+module_param(firmware, charp, 0664);
+MODULE_PARM_DESC(firmware, "RBF file under /lib/firmware for loading via CvP.");
+
+static int chkcfg; /* use value 1 for debugging only */
+module_param(chkcfg, int, 0664);
+MODULE_PARM_DESC(chkcfg, "1 - check CvP status, 0 - skip checking (default 0)");
+
+struct stratix_cvp_conf {
+	struct fpga_manager	*mgr;
+	struct pci_dev		*pci_dev;
+	void __iomem		*map;
+	resource_size_t		map_base;
+	resource_size_t		map_len;
+};
+
+static enum fpga_mgr_states stratix_cvp_state(struct fpga_manager *mgr)
+{
+	return mgr->state;
+}
+
+static int stratix_cvp_write_init(struct fpga_manager *mgr,
+				  struct fpga_image_info *info,
+				  const char *buf, size_t count)
+{
+	struct stratix_cvp_conf *conf = mgr->priv;
+	struct pci_bus *bus = conf->pci_dev->bus;
+	struct pci_dev *pdev = conf->pci_dev;
+	int delay_us, i;
+	u32 val32;
+	u16 val16;
+	u32 data;
+
+	if (info && info->flags & FPGA_MGR_PARTIAL_RECONFIG) {
+		dev_err(&mgr->dev, "Partial reconfiguration not supported.\n");
+		return -EINVAL;
+	}
+
+	/*
+	 * STEP 1 - read CVP status and check CVP_EN flag
+	 */
+	pci_bus_read_config_word(bus, FNC, VSEC_CVP_STATUS, &val16);
+	if (!(val16 & VSEC_CVP_STATUS_CVP_EN)) {
+		dev_err(&mgr->dev, "CVP mode off: 0x%04x\n", val16);
+		return -EINVAL;
+	}
+
+	/*
+	 * STEP 2
+	 * - set HIP_CLK_SEL and CVP_MODE (must be set in the order mentioned)
+	 */
+	/* switch from fabric to PMA clock */
+	pci_read_config_dword(pdev, VSEC_CVP_MODE_CTRL, &val32);
+	val32 |= VSEC_CVP_MODE_CTRL_HIP_CLK_SEL;
+	pci_write_config_dword(pdev, VSEC_CVP_MODE_CTRL, val32);
+
+	/* set CVP mode */
+	pci_read_config_dword(pdev, VSEC_CVP_MODE_CTRL, &val32);
+	val32 |= VSEC_CVP_MODE_CTRL_CVPMODE;
+	pci_write_config_dword(pdev, VSEC_CVP_MODE_CTRL, val32);
+
+	/*
+	 * STEP 3
+	 * - set CVP_NUMCLKS to 1 and issue CVP_DUMMY_WR dummy writes to the HIP
+	 */
+	pci_read_config_dword(pdev, VSEC_CVP_MODE_CTRL, &val32);
+	val32 &= ~VSEC_CVP_MODE_CTRL_NUMCLKS;
+	val32 |= 0x01 << 8;	/* 1 clock */
+	pci_write_config_dword(pdev, VSEC_CVP_MODE_CTRL, val32);
+
+	/* dummy memory write to switch from internal clock to CVP clock */
+	val32 = 0xdeadbeef;
+	if (conf->map) {
+		u32 *map = conf->map;
+
+		for (i = 0; i < CVP_DUMMY_WR; i++)
+			*map++ = val32; /* use MemoryWrite */
+	} else {
+		for (i = 0; i < CVP_DUMMY_WR; i++)
+			pci_write_config_dword(pdev, VSEC_CVP_DATA, val32);
+	}
+
+	/*
+	 * STEP 4 - set CVP_CONFIG bit
+	 */
+	pci_read_config_dword(pdev, VSEC_CVP_PROG_CTRL, &val32);
+	/* request control block to begin transfer using CVP */
+	val32 |= VSEC_CVP_PROG_CTRL_CONFIG;
+	pci_write_config_dword(pdev, VSEC_CVP_PROG_CTRL, val32);
+
+	/*
+	 * STEP 5 - poll CVP_CONFIG READY
+	 */
+	delay_us = 0;
+	while (1) {
+		pci_read_config_word(pdev, VSEC_CVP_STATUS, &val16);
+		if ((val16 & VSEC_CVP_STATUS_CFG_RDY) ==
+		    VSEC_CVP_STATUS_CFG_RDY)
+			break;
+
+		udelay(1); /* wait 1us */
+
+		if (delay_us++ > TIMEOUT_IN_US) {
+			dev_warn(&mgr->dev, "CVP_CONFIG_READY == 1 timeout\n");
+			return -ETIMEDOUT;
+		}
+	}
+
+	/*
+	 * STEP 6
+	 * - set CVP_NUMCLKS to 1 and issue CVP_DUMMY_WR dummy writes to the HIP
+	 */
+	pci_read_config_dword(pdev, VSEC_CVP_MODE_CTRL, &val32);
+	val32 &= ~VSEC_CVP_MODE_CTRL_NUMCLKS;
+	val32 |= 0x01 << 8; /* 1 clock */
+	pci_write_config_dword(pdev, VSEC_CVP_MODE_CTRL, val32);
+
+	/* dummy memory write to switch from internal clock to CVP clock */
+	val32 = 0xdeadbeef;
+	if (conf->map) {
+		u32 *map = conf->map;
+
+		for (i = 0; i < CVP_DUMMY_WR; i++)
+			*map++ = val32; /* use MemoryWrite */
+	} else {
+		for (i = 0; i < CVP_DUMMY_WR; i++)
+			pci_write_config_dword(pdev, VSEC_CVP_DATA, val32);
+	}
+
+	/*
+	 * STEP 7 - set START_XFER
+	 */
+	pci_read_config_dword(pdev, VSEC_CVP_PROG_CTRL, &val32);
+	val32 |= VSEC_CVP_PROG_CTRL_START_XFER;
+	pci_write_config_dword(pdev, VSEC_CVP_PROG_CTRL, val32);
+
+	/*
+	 * STEP 8 (start transfer)
+	 * check required bitstream type - read CVP status and set CVP_NUMCLKS
+	 * accordingly
+	 *	Compressed	Encrypted	CVP_NUMCLKS
+	 *	No		No		1
+	 *	Yes		No		8
+	 *	No		Yes		4
+	 *	Yes		Yes		8
+	 */
+	pci_read_config_word(pdev, VSEC_CVP_STATUS, &val16);
+	val16 &= (VSEC_CVP_STATUS_DATA_ENC | VSEC_CVP_STATUS_DATA_COMP);
+	switch (val16) {
+	case VSEC_CVP_STATUS_DATA_ENC:
+		data = 4;
+		break;
+	case VSEC_CVP_STATUS_DATA_COMP:
+	case (VSEC_CVP_STATUS_DATA_ENC | VSEC_CVP_STATUS_DATA_COMP):
+		data = 8;
+		break;
+	default:
+		data = 1;
+		break;
+	}
+
+	/* write number of CVP clock cycles according to bitstream type */
+	pci_read_config_dword(pdev, VSEC_CVP_MODE_CTRL, &val32);
+	val32 &= ~VSEC_CVP_MODE_CTRL_NUMCLKS;
+	val32 |= data << 8;	/* bitstream specific clock count */
+	pci_write_config_dword(pdev, VSEC_CVP_MODE_CTRL, val32);
+
+	return 0;
+}
+
+static inline int stratix_cvp_chk_cfg_error(struct fpga_manager *mgr,
+					    size_t bytes)
+{
+	struct stratix_cvp_conf *conf = mgr->priv;
+	u16 val16;
+
+	/*
+	 * STEP 10 (optional) - check CVP_CONFIG_ERROR flag
+	 */
+	pci_read_config_word(conf->pci_dev, VSEC_CVP_STATUS, &val16);
+	if (val16 & VSEC_CVP_STATUS_CFG_ERR) {
+		dev_err(&mgr->dev, " CVP_CONFIG_ERROR after %d bytes!\n",
+			bytes);
+		return -EPROTO;
+	}
+	return 0;
+}
+
+static int stratix_cvp_write(struct fpga_manager *mgr, const char *buf,
+			     size_t count)
+{
+	struct stratix_cvp_conf *conf = mgr->priv;
+	struct pci_dev *pdev = conf->pci_dev;
+	const u32 *data, *data_end;
+	size_t bytes = 0;
+	int status = 0;
+
+	/*
+	 * STEP 9
+	 * - write 32-bit configuration data from POF file to CVP data register
+	 */
+	data = (u32 *)buf;
+	data_end = (u32 *)((char *)buf + count);
+
+	if (conf->map) {
+		u32 *map = conf->map;
+
+		while (data < data_end) {
+			*map = *data++;
+			bytes += 4;
+
+			/*
+			 * STEP 10 (optional) and STEP 11
+			 * - check error flag
+			 * - loop until data transfer completed
+			 */
+			if (chkcfg) {
+				status = stratix_cvp_chk_cfg_error(mgr, bytes);
+				if (status < 0)
+					break;
+			}
+		}
+		return status;
+	}
+
+	while (data < data_end) {
+		pci_write_config_dword(pdev, VSEC_CVP_DATA, *data++);
+		bytes += 4;
+
+		/*
+		 * STEP 10 (optional) and STEP 11
+		 * - check error flag
+		 * - loop until data transfer completed
+		 */
+		if (chkcfg) {
+			status = stratix_cvp_chk_cfg_error(mgr, bytes);
+			if (status < 0)
+				break;
+		}
+	}
+
+	return status;
+}
+
+static int stratix_cvp_write_complete(struct fpga_manager *mgr,
+				      struct fpga_image_info *info)
+{
+	struct stratix_cvp_conf *conf = mgr->priv;
+	struct pci_dev *pdev = conf->pci_dev;
+	int status = 0;
+	int delay_us, i;
+	u32 val32;
+	u16 status_msk;
+	u16 val16;
+
+	/*
+	 * STEP 12 - reset START_XFER bit
+	 */
+	pci_read_config_dword(pdev, VSEC_CVP_PROG_CTRL, &val32);
+	val32 &= ~VSEC_CVP_PROG_CTRL_START_XFER;
+	pci_write_config_dword(pdev, VSEC_CVP_PROG_CTRL, val32);
+
+	/*
+	 * STEP 13 - reset CVP_CONFIG bit
+	 */
+	val32 &= ~VSEC_CVP_PROG_CTRL_CONFIG;
+	pci_write_config_dword(pdev, VSEC_CVP_PROG_CTRL, val32);
+
+	/*
+	 * STEP 14
+	 * - set CVP_NUMCLKS to 0x01 and then issue CVP_DUMMY_WR dummy
+	 *   writes to the HIP
+	 */
+	pci_read_config_dword(pdev, VSEC_CVP_MODE_CTRL, &val32);
+	val32 &= ~VSEC_CVP_MODE_CTRL_NUMCLKS;
+	/* set number of CVP clock cycles for every CVP Data Register Write */
+	val32 |= 0x01 << 8;	/* 1 clock */
+	pci_write_config_dword(pdev, VSEC_CVP_MODE_CTRL, val32);
+
+	/* dummy memory write to switch from CVP clock to internal clock */
+	val32 = 0xdeadbeef;
+	if (conf->map) {
+		u32 *map = conf->map;
+
+		for (i = 0; i < CVP_DUMMY_WR; i++)
+			*map++ = val32; /* use MemoryWrite */
+	} else {
+		for (i = 0; i < CVP_DUMMY_WR; i++)
+			pci_write_config_dword(pdev, VSEC_CVP_DATA, val32);
+	}
+
+	/*
+	 * STEP 15 - poll CVP_CONFIG_READY bit
+	 */
+	delay_us = 0;
+	while (1) {
+		pci_read_config_word(pdev, VSEC_CVP_STATUS, &val16);
+		if ((val16 & VSEC_CVP_STATUS_CFG_RDY) == 0)
+			break;
+
+		udelay(1);	/* wait 1us */
+
+		if (delay_us++ > TIMEOUT_IN_US) {
+			dev_warn(&mgr->dev, "CVP_CONFIG_READY == 0 timeout\n");
+			status = -ETIME;
+			break;
+		}
+	}
+
+	if (status < 0)
+		return status;
+
+	/*
+	 * STEP 16 - check CVP_CONFIG_ERROR_LATCHED bit
+	 */
+	pci_read_config_dword(pdev, VSEC_UNCOR_ERR_STATUS, &val32);
+	if (val32 & VSEC_UNCOR_ERR_CVP_CFG_ERR) {
+		dev_err(&mgr->dev, " detected CVP_CONFIG_ERROR_LATCHED!\n");
+		return -EFAULT;
+	}
+
+	/*
+	 * STEP 17 - reset CVP_MODE and HIP_CLK_SEL bit
+	 */
+	pci_read_config_dword(pdev, VSEC_CVP_MODE_CTRL, &val32);
+	val32 &= ~VSEC_CVP_MODE_CTRL_HIP_CLK_SEL;
+	val32 &= ~VSEC_CVP_MODE_CTRL_CVPMODE;
+	pci_write_config_dword(pdev, VSEC_CVP_MODE_CTRL, val32);
+
+	/*
+	 * STEP 18 - poll PLD_CLK_IN_USE and USER_MODE bits
+	 */
+	delay_us = 0;
+	status_msk = VSEC_CVP_STATUS_PLD_CLK_IN_USE | VSEC_CVP_STATUS_USERMODE;
+	while (1) {
+		pci_read_config_word(pdev, VSEC_CVP_STATUS, &val16);
+		if ((val16 & status_msk) == status_msk)
+			break;
+
+		udelay(1); /* wait 1us */
+
+		if (delay_us++ > TIMEOUT_IN_US) {
+			dev_warn(&mgr->dev, "PLD_CLK_IN_USE|USERMODE timeout\n");
+			status = -ETIME;
+			break;
+		}
+	}
+
+	return status;
+}
+
+static const struct fpga_manager_ops stratix_cvp_ops = {
+	.state		= stratix_cvp_state,
+	.write_init	= stratix_cvp_write_init,
+	.write		= stratix_cvp_write,
+	.write_complete	= stratix_cvp_write_complete,
+};
+
+static int stratix_cvp_probe(struct pci_dev *pdev,
+			     const struct pci_device_id *dev_id)
+{
+	struct stratix_cvp_conf *conf;
+	u16 cmd, val16;
+	int ret;
+
+	/* Enable memory BAR access */
+	pci_read_config_word(pdev, PCI_COMMAND, &cmd);
+	if (!(cmd & PCI_COMMAND_MEMORY)) {
+		cmd |= PCI_COMMAND_MEMORY;
+		pci_write_config_word(pdev, PCI_COMMAND, cmd);
+	}
+
+	conf = devm_kzalloc(&pdev->dev, sizeof(*conf), GFP_KERNEL);
+	if (!conf) {
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	pci_bus_read_config_word(pdev->bus, FNC, VSEC_PCIE_EXT_CAP_ID, &val16);
+	if (val16 != VSEC_PCIE_EXT_CAP_ID_VAL) {
+		dev_err(&pdev->dev, "Wrong EXT_CAP_ID value 0x%x\n", val16);
+		ret = -ENODEV;
+		goto err;
+	}
+
+	conf->pci_dev = pdev;
+	conf->map_base = pci_resource_start(pdev, CVP_BAR);
+	conf->map_len = pci_resource_len(pdev, CVP_BAR);
+
+	if (pci_request_region(pdev, CVP_BAR, "CVP") < 0) {
+		dev_err(&pdev->dev, "Requesting CVP BAR region failed\n");
+		ret = -ENODEV;
+		goto err;
+	}
+
+	conf->map = ioremap_nocache(conf->map_base, conf->map_len);
+	if (!conf->map)
+		dev_warn(&pdev->dev, "Mapping CVP BAR failed\n");
+
+	ret = fpga_mgr_register(&pdev->dev, STRATIX_V_CVP_MGR_NAME,
+				&stratix_cvp_ops, conf);
+	if (ret)
+		goto err_unmap;
+
+	conf->mgr = fpga_mgr_get(&pdev->dev);
+	if (IS_ERR(conf->mgr)) {
+		dev_err(&pdev->dev, "Getting fpga mgr reference failed\n");
+		ret = -ENODEV;
+		goto err_unmap;
+	}
+
+	ret = fpga_mgr_firmware_load(conf->mgr, NULL, firmware);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to load fpga image\n");
+		goto err_mgr;
+	}
+
+	return 0;
+
+err_mgr:
+	fpga_mgr_put(conf->mgr);
+	fpga_mgr_unregister(&pdev->dev);
+err_unmap:
+	iounmap(conf->map);
+	pci_release_region(pdev, CVP_BAR);
+err:
+	cmd &= ~PCI_COMMAND_MEMORY;
+	pci_write_config_word(pdev, PCI_COMMAND, cmd);
+	return ret;
+}
+
+static void stratix_cvp_remove(struct pci_dev *pdev)
+{
+	struct fpga_manager *mgr = pci_get_drvdata(pdev);
+	struct stratix_cvp_conf *conf = mgr->priv;
+	u16 cmd;
+
+	fpga_mgr_put(conf->mgr);
+	fpga_mgr_unregister(&pdev->dev);
+	iounmap(conf->map);
+	pci_release_region(pdev, CVP_BAR);
+	pci_read_config_word(pdev, PCI_COMMAND, &cmd);
+	cmd &= ~PCI_COMMAND_MEMORY;
+	pci_write_config_word(pdev, PCI_COMMAND, cmd);
+}
+
+#define PCI_VENDOR_ID_ALTERA	0x1172
+#define PCI_DEVICE_ID_FPGA	0xe001
+
+static struct pci_device_id stratix_cvp_id_tbl[] = {
+	{ PCI_VDEVICE(ALTERA, PCI_DEVICE_ID_FPGA) },
+	{ }
+};
+
+static struct pci_driver stratix_cvp_driver = {
+	.name   = DRV_NAME,
+	.id_table = stratix_cvp_id_tbl,
+	.probe  = stratix_cvp_probe,
+	.remove = stratix_cvp_remove,
+};
+
+module_pci_driver(stratix_cvp_driver)
+
+MODULE_DEVICE_TABLE(pci, stratix_cvp_id_tbl);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Anatolij Gustschin <agust@denx.de>");
+MODULE_DESCRIPTION("Module to load Altera FPGA over CvP");
