diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
index 1af94e2..3bdbc51 100644
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -464,6 +464,17 @@ if CRYPTO_DEV_CCP
 	source "drivers/crypto/ccp/Kconfig"
 endif
 
+config CRYPTO_DEV_PSP
+	bool "Support for AMD Platform Security Processor"
+	depends on X86 && PCI
+	help
+	  The AMD Platform Security Processor provides hardware key-
+	  management services for VMGuard encrypted memory.
+
+if CRYPTO_DEV_PSP
+	source "drivers/crypto/psp/Kconfig"
+endif
+
 config CRYPTO_DEV_MXS_DCP
 	tristate "Support for Freescale MXS DCP"
 	depends on (ARCH_MXS || ARCH_MXC)
diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile
index 3c6432d..1ea1e08 100644
--- a/drivers/crypto/Makefile
+++ b/drivers/crypto/Makefile
@@ -3,6 +3,7 @@ obj-$(CONFIG_CRYPTO_DEV_ATMEL_SHA) += atmel-sha.o
 obj-$(CONFIG_CRYPTO_DEV_ATMEL_TDES) += atmel-tdes.o
 obj-$(CONFIG_CRYPTO_DEV_BFIN_CRC) += bfin_crc.o
 obj-$(CONFIG_CRYPTO_DEV_CCP) += ccp/
+obj-$(CONFIG_CRYPTO_DEV_PSP) += psp/
 obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM) += caam/
 obj-$(CONFIG_CRYPTO_DEV_GEODE) += geode-aes.o
 obj-$(CONFIG_CRYPTO_DEV_HIFN_795X) += hifn_795x.o
diff --git a/drivers/crypto/psp/Kconfig b/drivers/crypto/psp/Kconfig
new file mode 100644
index 0000000..acd9b87
--- /dev/null
+++ b/drivers/crypto/psp/Kconfig
@@ -0,0 +1,8 @@
+config CRYPTO_DEV_PSP_DD
+	tristate "PSP Key Management device driver"
+	depends on CRYPTO_DEV_PSP
+	default m
+	help
+	  Provides the interface to use the AMD PSP key management APIs
+	  for use with the AMD Secure Enhanced Virtualization. If you
+	  choose 'M' here, this module will be called psp.
diff --git a/drivers/crypto/psp/Makefile b/drivers/crypto/psp/Makefile
new file mode 100644
index 0000000..1b7d00c
--- /dev/null
+++ b/drivers/crypto/psp/Makefile
@@ -0,0 +1,3 @@
+obj-$(CONFIG_CRYPTO_DEV_PSP_DD) += psp.o
+psp-objs := psp-dev.o psp-ops.o
+psp-$(CONFIG_PCI) += psp-pci.o
diff --git a/drivers/crypto/psp/psp-dev.c b/drivers/crypto/psp/psp-dev.c
new file mode 100644
index 0000000..65d5c7e
--- /dev/null
+++ b/drivers/crypto/psp/psp-dev.c
@@ -0,0 +1,220 @@
+/*
+ * AMD Cryptographic Coprocessor (CCP) driver
+ *
+ * Copyright (C) 2016 Advanced Micro Devices, Inc.
+ *
+ * Author: Tom Lendacky <thomas.lendacky@amd.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <linux/string.h>
+#include <linux/wait.h>
+
+#include "psp-dev.h"
+
+MODULE_AUTHOR("Advanced Micro Devices, Inc.");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("0.1.0");
+MODULE_DESCRIPTION("AMD VMGuard key-management driver prototype");
+
+static struct psp_device *psp_master;
+
+static LIST_HEAD(psp_devs);
+static DEFINE_SPINLOCK(psp_devs_lock);
+
+static atomic_t psp_id;
+
+static void psp_add_device(struct psp_device *psp)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&psp_devs_lock, flags);
+
+	list_add_tail(&psp->entry, &psp_devs);
+	psp_master = psp->get_master(&psp_devs);
+
+	spin_unlock_irqrestore(&psp_devs_lock, flags);
+}
+
+static void psp_del_device(struct psp_device *psp)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&psp_devs_lock, flags);
+
+	list_del(&psp->entry);
+	if (psp == psp_master)
+		psp_master = NULL;
+
+	spin_unlock_irqrestore(&psp_devs_lock, flags);
+}
+
+static void psp_check_support(struct psp_device *psp)
+{
+	if (ioread32(psp->io_regs + PSP_CMDRESP))
+		psp->sev_enabled = 1;
+}
+
+/**
+ * psp_get_master_device - returns a pointer to the PSP master device structure
+ *
+ * Returns NULL if a PSP master device is not present, PSP device structure
+ * otherwise.
+ */
+struct psp_device *psp_get_master_device(void)
+{
+	return psp_master;
+}
+EXPORT_SYMBOL_GPL(psp_get_master_device);
+
+/**
+ * psp_get_device - returns a pointer to the PSP device structure
+ *
+ * Returns NULL if a PSP device is not present, PSP device structure otherwise.
+ */
+struct psp_device *psp_get_device(void)
+{
+	struct psp_device *psp = NULL;
+	unsigned long flags;
+
+	spin_lock_irqsave(&psp_devs_lock, flags);
+
+	if (list_empty(&psp_devs))
+		goto unlock;
+
+	psp = list_first_entry(&psp_devs, struct psp_device, entry);
+
+unlock:
+	spin_unlock_irqrestore(&psp_devs_lock, flags);
+
+	return psp;
+}
+EXPORT_SYMBOL_GPL(psp_get_device);
+
+/**
+ * psp_alloc_struct - allocate and initialize the psp_device struct
+ *
+ * @dev: device struct of the PSP
+ */
+struct psp_device *psp_alloc_struct(struct device *dev)
+{
+	struct psp_device *psp;
+
+	psp = devm_kzalloc(dev, sizeof(*psp), GFP_KERNEL);
+	if (psp == NULL) {
+		dev_err(dev, "unable to allocate device struct\n");
+		return NULL;
+	}
+	psp->dev = dev;
+
+	psp->id = atomic_inc_return(&psp_id);
+	snprintf(psp->name, sizeof(psp->name), "psp%u", psp->id);
+
+	init_waitqueue_head(&psp->int_queue);
+
+	return psp;
+}
+
+/**
+ * psp_init - initialize the PSP device
+ *
+ * @psp: psp_device struct
+ */
+int psp_init(struct psp_device *psp)
+{
+	int ret;
+
+	psp_check_support(psp);
+
+	/* Disable and clear interrupts until ready */
+	iowrite32(0, psp->io_regs + PSP_P2CMSG_INTEN);
+	iowrite32(0xffffffff, psp->io_regs + PSP_P2CMSG_INTSTS);
+
+	/* Request an irq */
+	ret = psp->get_irq(psp);
+	if (ret) {
+		dev_err(psp->dev, "unable to allocate IRQ\n");
+		return ret;
+	}
+
+	/* Make the device struct available */
+	psp_add_device(psp);
+
+	/* Enable interrupts */
+	iowrite32(1 << PSP_CMD_COMPLETE_REG, psp->io_regs + PSP_P2CMSG_INTEN);
+
+	ret = psp_ops_init(psp);
+	if (ret)
+		dev_err(psp->dev, "psp_ops_init returned %d\n", ret);
+
+	return 0;
+}
+
+/**
+ * psp_destroy - tear down the PSP device
+ *
+ * @psp: psp_device struct
+ */
+void psp_destroy(struct psp_device *psp)
+{
+	psp_ops_exit(psp);
+
+	/* Remove general access to the device struct */
+	psp_del_device(psp);
+
+	psp->free_irq(psp);
+}
+
+/**
+ * psp_irq_handler - handle interrupts generated by the PSP device
+ *
+ * @irq: the irq associated with the interrupt
+ * @data: the data value supplied when the irq was created
+ */
+irqreturn_t psp_irq_handler(int irq, void *data)
+{
+	struct device *dev = data;
+	struct psp_device *psp = dev_get_drvdata(dev);
+	unsigned int status;
+
+	status = ioread32(psp->io_regs + PSP_P2CMSG_INTSTS);
+	if (status & (1 << PSP_CMD_COMPLETE_REG)) {
+		int reg;
+
+		reg = ioread32(psp->io_regs + PSP_CMDRESP);
+		if (reg & PSP_CMDRESP_RESP) {
+			psp->int_rcvd = 1;
+			wake_up_interruptible(&psp->int_queue);
+		}
+	}
+
+	iowrite32(status, psp->io_regs + PSP_P2CMSG_INTSTS);
+
+	return IRQ_HANDLED;
+}
+
+static int __init psp_mod_init(void)
+{
+	int ret;
+
+	ret = psp_pci_init();
+	if (ret)
+		return ret;
+
+	return 0;
+}
+module_init(psp_mod_init);
+
+static void __exit psp_mod_exit(void)
+{
+	psp_pci_exit();
+}
+module_exit(psp_mod_exit);
diff --git a/drivers/crypto/psp/psp-dev.h b/drivers/crypto/psp/psp-dev.h
new file mode 100644
index 0000000..bb75ca2
--- /dev/null
+++ b/drivers/crypto/psp/psp-dev.h
@@ -0,0 +1,95 @@
+
+#ifndef __PSP_DEV_H__
+#define __PSP_DEV_H__
+
+#include <linux/device.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+#include <linux/mutex.h>
+#include <linux/list.h>
+#include <linux/wait.h>
+#include <linux/dmapool.h>
+#include <linux/hw_random.h>
+#include <linux/interrupt.h>
+#include <linux/miscdevice.h>
+
+#define PSP_P2CMSG_INTEN		0x0110
+#define PSP_P2CMSG_INTSTS		0x0114
+
+#define PSP_C2PMSG_ATTR_0		0x0118
+#define PSP_C2PMSG_ATTR_1		0x011c
+#define PSP_C2PMSG_ATTR_2		0x0120
+#define PSP_C2PMSG_ATTR_3		0x0124
+#define PSP_P2CMSG_ATTR_0		0x0128
+
+#define PSP_C2PMSG(_num)		((_num) << 2)
+#define PSP_CMDRESP			PSP_C2PMSG(32)
+#define PSP_CMDBUFF_ADDR_LO		PSP_C2PMSG(56)
+#define PSP_CMDBUFF_ADDR_HI 		PSP_C2PMSG(57)
+
+#define PSP_P2CMSG(_num)		(_num << 2)
+#define PSP_CMD_COMPLETE_REG		1
+#define PSP_CMD_COMPLETE		PSP_P2CMSG(PSP_CMD_COMPLETE_REG)
+
+#define PSP_CMDRESP_CMD_SHIFT		16
+#define PSP_CMDRESP_IOC			BIT(0)
+#define PSP_CMDRESP_RESP		BIT(31)
+#define PSP_CMDRESP_ERR_MASK		0xffff
+
+#define PSP_DRIVER_NAME			"psp"
+
+struct psp_device {
+	struct list_head entry;
+
+	struct device *dev;
+
+	unsigned int id;
+	char name[32];
+
+	struct dentry *debugfs;
+	struct miscdevice misc;
+
+	unsigned int sev_enabled;
+
+	/*
+	 * Bus-specific device information
+	 */
+	void *dev_specific;
+	int (*get_irq)(struct psp_device *);
+	void (*free_irq)(struct psp_device *);
+	unsigned int irq;
+	struct psp_device *(*get_master)(struct list_head *list);
+
+	/*
+	 * I/O area used for device communication. Writing to the
+	 * mailbox registers generates an interrupt on the PSP.
+	 */
+	void __iomem *io_map;
+	void __iomem *io_regs;
+
+	/* Interrupt wait queue */
+	wait_queue_head_t int_queue;
+	unsigned int int_rcvd;
+};
+
+struct psp_device *psp_get_master_device(void);
+struct psp_device *psp_get_device(void);
+
+#ifdef CONFIG_PCI
+int psp_pci_init(void);
+void psp_pci_exit(void);
+#else
+static inline int psp_pci_init(void) { return 0; }
+static inline void psp_pci_exit(void) { }
+#endif
+
+struct psp_device *psp_alloc_struct(struct device *dev);
+int psp_init(struct psp_device *psp);
+void psp_destroy(struct psp_device *psp);
+
+int psp_ops_init(struct psp_device *psp);
+void psp_ops_exit(struct psp_device *psp);
+
+irqreturn_t psp_irq_handler(int irq, void *data);
+
+#endif /* PSP_DEV_H */
diff --git a/drivers/crypto/psp/psp-ops.c b/drivers/crypto/psp/psp-ops.c
new file mode 100644
index 0000000..81e8dc8
--- /dev/null
+++ b/drivers/crypto/psp/psp-ops.c
@@ -0,0 +1,454 @@
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/delay.h>
+#include <linux/jiffies.h>
+#include <linux/wait.h>
+#include <linux/mutex.h>
+#include <linux/ccp-psp.h>
+
+#include "psp-dev.h"
+
+static unsigned int psp_poll = 0;
+module_param(psp_poll, uint, 0444);
+MODULE_PARM_DESC(psp_poll, "Poll for command completion - any non-zero value");
+
+#define PSP_DEFAULT_TIMEOUT	2
+
+DEFINE_MUTEX(psp_cmd_mutex);
+
+static int psp_wait_cmd_poll(struct psp_device *psp, unsigned int timeout,
+			     unsigned int *reg)
+{
+	int wait = timeout * 10;	/* 100ms sleep => timeout * 10 */
+
+	while (--wait) {
+		msleep(100);
+
+		*reg = ioread32(psp->io_regs + PSP_CMDRESP);
+		if (*reg & PSP_CMDRESP_RESP)
+			break;
+	}
+
+	if (!wait) {
+		dev_err(psp->dev, "psp command timed out\n");
+		return -ETIMEDOUT;
+	}
+
+	return 0;
+}
+
+static int psp_wait_cmd_ioc(struct psp_device *psp, unsigned int timeout,
+			    unsigned int *reg)
+{
+	unsigned long jiffie_timeout = timeout;
+	long ret;
+
+	jiffie_timeout *= HZ;
+
+	ret = wait_event_interruptible_timeout(psp->int_queue, psp->int_rcvd,
+					       jiffie_timeout);
+	if (ret <= 0) {
+		dev_err(psp->dev, "psp command timed out\n");
+		return -ETIMEDOUT;
+	}
+
+	psp->int_rcvd = 0;
+
+	*reg = ioread32(psp->io_regs + PSP_CMDRESP);
+
+	return 0;
+}
+
+static int psp_wait_cmd(struct psp_device *psp, unsigned int timeout,
+			unsigned int *reg)
+{
+	return (*reg & PSP_CMDRESP_IOC) ? psp_wait_cmd_ioc(psp, timeout, reg)
+					: psp_wait_cmd_poll(psp, timeout, reg);
+}
+
+static int psp_issue_cmd(enum psp_cmd cmd, void *data, unsigned int timeout,
+			 int *psp_ret)
+{
+	struct psp_device *psp = psp_get_master_device();
+	unsigned int phys_lsb, phys_msb;
+	unsigned int reg, ret;
+
+	if (psp_ret)
+		*psp_ret = 0;
+
+	if (!psp)
+		return -ENODEV;
+
+	if (!psp->sev_enabled)
+		return -ENOTSUPP;
+
+	/* Set the physical address for the PSP */
+	phys_lsb = data ? lower_32_bits(__psp_pa(data)) : 0;
+	phys_msb = data ? upper_32_bits(__psp_pa(data)) : 0;
+
+	/* Only one command at a time... */
+	mutex_lock(&psp_cmd_mutex);
+
+	iowrite32(phys_lsb, psp->io_regs + PSP_CMDBUFF_ADDR_LO);
+	iowrite32(phys_msb, psp->io_regs + PSP_CMDBUFF_ADDR_HI);
+	wmb();
+
+	reg = cmd;
+	reg <<= PSP_CMDRESP_CMD_SHIFT;
+	reg |= psp_poll ? 0 : PSP_CMDRESP_IOC;
+	iowrite32(reg, psp->io_regs + PSP_CMDRESP);
+
+	ret = psp_wait_cmd(psp, timeout, &reg);
+	if (ret)
+		goto unlock;
+
+	if (psp_ret)
+		*psp_ret = reg & PSP_CMDRESP_ERR_MASK;
+
+	if (reg & PSP_CMDRESP_ERR_MASK) {
+		dev_err(psp->dev, "psp command %u failed (%#010x)\n", cmd, reg & PSP_CMDRESP_ERR_MASK);
+		ret = -EIO;
+	}
+
+unlock:
+	mutex_unlock(&psp_cmd_mutex);
+
+	return ret;
+}
+
+int psp_platform_init(struct psp_data_init *data, int *psp_ret)
+{
+	return psp_issue_cmd(PSP_CMD_INIT, data, PSP_DEFAULT_TIMEOUT,
+			     psp_ret);
+}
+EXPORT_SYMBOL_GPL(psp_platform_init);
+
+int psp_platform_shutdown(int *psp_ret)
+{
+	return psp_issue_cmd(PSP_CMD_SHUTDOWN, NULL, PSP_DEFAULT_TIMEOUT,
+			     psp_ret);
+}
+EXPORT_SYMBOL_GPL(psp_platform_shutdown);
+
+int psp_platform_status(struct psp_data_status *data, int *psp_ret)
+{
+	return psp_issue_cmd(PSP_CMD_PLATFORM_STATUS, data,
+			     PSP_DEFAULT_TIMEOUT, psp_ret);
+}
+EXPORT_SYMBOL_GPL(psp_platform_status);
+
+int psp_guest_launch_start(struct psp_data_launch_start *data, int *psp_ret)
+{
+	return psp_issue_cmd(PSP_CMD_LAUNCH_START, data, PSP_DEFAULT_TIMEOUT,
+			     psp_ret);
+}
+EXPORT_SYMBOL_GPL(psp_guest_launch_start);
+
+int psp_guest_launch_update(struct psp_data_launch_update *data,
+			    unsigned int timeout, int *psp_ret)
+{
+	return psp_issue_cmd(PSP_CMD_LAUNCH_UPDATE, data, timeout, psp_ret);
+}
+EXPORT_SYMBOL_GPL(psp_guest_launch_update);
+
+int psp_guest_launch_finish(struct psp_data_launch_finish *data, int *psp_ret)
+{
+	return psp_issue_cmd(PSP_CMD_LAUNCH_FINISH, data, PSP_DEFAULT_TIMEOUT,
+			     psp_ret);
+}
+EXPORT_SYMBOL_GPL(psp_guest_launch_finish);
+
+int psp_guest_activate(struct psp_data_activate *data, int *psp_ret)
+{
+	return psp_issue_cmd(PSP_CMD_ACTIVATE, data, PSP_DEFAULT_TIMEOUT,
+			     psp_ret);
+}
+EXPORT_SYMBOL_GPL(psp_guest_activate);
+
+int psp_guest_deactivate(struct psp_data_deactivate *data, int *psp_ret)
+{
+	return psp_issue_cmd(PSP_CMD_DEACTIVATE, data, PSP_DEFAULT_TIMEOUT,
+			     psp_ret);
+}
+EXPORT_SYMBOL_GPL(psp_guest_deactivate);
+
+int psp_guest_df_flush(int *psp_ret)
+{
+	return psp_issue_cmd(PSP_CMD_DF_FLUSH, NULL, PSP_DEFAULT_TIMEOUT,
+			     psp_ret);
+}
+EXPORT_SYMBOL_GPL(psp_guest_df_flush);
+
+int psp_guest_decommission(struct psp_data_decommission *data, int *psp_ret)
+{
+	return psp_issue_cmd(PSP_CMD_DECOMMISSION, data, PSP_DEFAULT_TIMEOUT,
+			     psp_ret);
+}
+EXPORT_SYMBOL_GPL(psp_guest_decommission);
+
+int psp_guest_status(struct psp_data_guest_status *data, int *psp_ret)
+{
+	return psp_issue_cmd(PSP_CMD_GUEST_STATUS, data, PSP_DEFAULT_TIMEOUT,
+			     psp_ret);
+}
+EXPORT_SYMBOL_GPL(psp_guest_status);
+
+int psp_dbg_decrypt(struct psp_data_dbg *data, int *psp_ret)
+{
+	return psp_issue_cmd(PSP_CMD_DBG_DECRYPT, data, PSP_DEFAULT_TIMEOUT,
+			     psp_ret);
+}
+EXPORT_SYMBOL_GPL(psp_dbg_decrypt);
+
+int psp_dbg_encrypt(struct psp_data_dbg *data, int *psp_ret)
+{
+	return psp_issue_cmd(PSP_CMD_DBG_ENCRYPT, data, PSP_DEFAULT_TIMEOUT,
+			     psp_ret);
+}
+EXPORT_SYMBOL_GPL(psp_dbg_encrypt);
+
+int psp_guest_receive_start(struct psp_data_receive_start *data, int *psp_ret)
+{
+	return psp_issue_cmd(PSP_CMD_RECEIVE_START, data, PSP_DEFAULT_TIMEOUT,
+			     psp_ret);
+}
+EXPORT_SYMBOL_GPL(psp_guest_receive_start);
+
+int psp_guest_receive_update(struct psp_data_receive_update *data,
+			    unsigned int timeout, int *psp_ret)
+{
+	return psp_issue_cmd(PSP_CMD_RECEIVE_UPDATE, data, timeout, psp_ret);
+}
+EXPORT_SYMBOL_GPL(psp_guest_receive_update);
+
+int psp_guest_receive_finish(struct psp_data_receive_finish *data, int *psp_ret)
+{
+	return psp_issue_cmd(PSP_CMD_RECEIVE_FINISH, data, PSP_DEFAULT_TIMEOUT,
+			     psp_ret);
+}
+EXPORT_SYMBOL_GPL(psp_guest_receive_finish);
+
+int psp_guest_send_start(struct psp_data_send_start *data, int *psp_ret)
+{
+	return psp_issue_cmd(PSP_CMD_SEND_START, data, PSP_DEFAULT_TIMEOUT,
+			     psp_ret);
+}
+EXPORT_SYMBOL_GPL(psp_guest_send_start);
+
+int psp_guest_send_update(struct psp_data_send_update *data,
+			    unsigned int timeout, int *psp_ret)
+{
+	return psp_issue_cmd(PSP_CMD_SEND_UPDATE, data, timeout, psp_ret);
+}
+EXPORT_SYMBOL_GPL(psp_guest_send_update);
+
+int psp_guest_send_finish(struct psp_data_send_finish *data, int *psp_ret)
+{
+	return psp_issue_cmd(PSP_CMD_SEND_FINISH, data, PSP_DEFAULT_TIMEOUT,
+			     psp_ret);
+}
+EXPORT_SYMBOL_GPL(psp_guest_send_finish);
+
+int psp_platform_pdh_gen(int *psp_ret)
+{
+	return psp_issue_cmd(PSP_CMD_PDH_GEN, NULL, PSP_DEFAULT_TIMEOUT,
+			     psp_ret);
+}
+EXPORT_SYMBOL_GPL(psp_platform_pdh_gen);
+
+int psp_platform_pdh_cert_export(struct psp_data_pdh_cert_export *data,
+				int *psp_ret)
+{
+	return psp_issue_cmd(PSP_CMD_PDH_CERT_EXPORT, data, PSP_DEFAULT_TIMEOUT,
+			     psp_ret);
+}
+EXPORT_SYMBOL_GPL(psp_platform_pdh_cert_export);
+
+int psp_platform_pek_gen(int *psp_ret)
+{
+	return psp_issue_cmd(PSP_CMD_PEK_GEN, NULL, PSP_DEFAULT_TIMEOUT,
+			     psp_ret);
+}
+EXPORT_SYMBOL_GPL(psp_platform_pek_gen);
+
+int psp_platform_pek_cert_import(struct psp_data_pek_cert_import *data,
+				 int *psp_ret)
+{
+	return psp_issue_cmd(PSP_CMD_PEK_CERT_IMPORT, data, PSP_DEFAULT_TIMEOUT,
+			     psp_ret);
+}
+EXPORT_SYMBOL_GPL(psp_platform_pek_cert_import);
+
+int psp_platform_pek_csr(struct psp_data_pek_csr *data, int *psp_ret)
+{
+	return psp_issue_cmd(PSP_CMD_PEK_CSR, data, PSP_DEFAULT_TIMEOUT,
+			     psp_ret);
+}
+EXPORT_SYMBOL_GPL(psp_platform_pek_csr);
+
+int psp_platform_factory_reset(int *psp_ret)
+{
+	return psp_issue_cmd(PSP_CMD_FACTORY_RESET, NULL, PSP_DEFAULT_TIMEOUT,
+			     psp_ret);
+}
+EXPORT_SYMBOL_GPL(psp_platform_factory_reset);
+
+static int psp_copy_to_user(void __user *argp, void *data, size_t size)
+{
+	int ret = 0;
+
+	if (copy_to_user(argp, data, size))
+		ret = -EFAULT;
+	free_pages_exact(data, size);
+
+	return ret;
+}
+
+static void *psp_copy_from_user(void __user *argp, size_t *size)
+{
+	u32 buffer_len;
+	void *data;
+
+	if (copy_from_user(&buffer_len, argp, sizeof(buffer_len)))
+		return ERR_PTR(-EFAULT);
+
+	data = alloc_pages_exact(buffer_len, GFP_KERNEL | __GFP_ZERO);
+	if (!data)
+		return ERR_PTR(-ENOMEM);
+	*size = buffer_len;
+
+	if (copy_from_user(data, argp, buffer_len)) {
+		free_pages_exact(data, *size);
+		return ERR_PTR(-EFAULT);
+	}
+
+	return data;
+}
+
+static long psp_ioctl(struct file *file, unsigned int ioctl, unsigned long arg)
+{
+	int ret = -EFAULT;
+	void *data = NULL;
+	size_t buffer_len = 0;
+	void __user *argp = (void __user *)arg;
+	struct psp_issue_cmd input;
+
+	if (ioctl != PSP_ISSUE_CMD)
+		return -EINVAL;
+
+	/* get input parameters */
+	if (copy_from_user(&input, argp, sizeof(struct psp_issue_cmd)))
+	       return -EFAULT;
+
+	if (input.cmd > PSP_CMD_MAX)
+		return -EINVAL;
+
+	switch (input.cmd) {
+
+	case PSP_CMD_INIT: {
+		struct psp_data_init *init;
+
+		data = psp_copy_from_user((void*)input.opaque, &buffer_len);
+		if (IS_ERR(data))
+			break;
+
+		init = data;
+		ret = psp_platform_init(init, &input.psp_ret);
+		break;
+	}
+	case PSP_CMD_SHUTDOWN: {
+		ret = psp_platform_shutdown(&input.psp_ret);
+		break;
+	}
+	case PSP_CMD_FACTORY_RESET: {
+		ret = psp_platform_factory_reset(&input.psp_ret);
+		break;
+	}
+	case PSP_CMD_PLATFORM_STATUS: {
+		struct psp_data_status *status;
+
+		data = psp_copy_from_user((void*)input.opaque, &buffer_len);
+		if (IS_ERR(data))
+			break;
+
+		status = data;
+		ret = psp_platform_status(status, &input.psp_ret);
+		break;
+	}
+	case PSP_CMD_PEK_GEN: {
+		ret = psp_platform_pek_gen(&input.psp_ret);
+		break;
+	}
+	case PSP_CMD_PEK_CSR: {
+		struct psp_data_pek_csr *pek_csr;
+
+		data = psp_copy_from_user((void*)input.opaque, &buffer_len);
+		if (IS_ERR(data))
+			break;
+
+		pek_csr = data;
+		ret = psp_platform_pek_csr(pek_csr, &input.psp_ret);
+		break;
+	}
+	case PSP_CMD_PEK_CERT_IMPORT: {
+		struct psp_data_pek_cert_import *import;
+
+		data = psp_copy_from_user((void*)input.opaque, &buffer_len);
+		if (IS_ERR(data))
+			break;
+
+		import = data;
+		ret = psp_platform_pek_cert_import(import, &input.psp_ret);
+		break;
+	}
+	case PSP_CMD_PDH_GEN: {
+		ret = psp_platform_pdh_gen(&input.psp_ret);
+		break;
+	}
+	case PSP_CMD_PDH_CERT_EXPORT: {
+		struct psp_data_pdh_cert_export *export;
+
+		data = psp_copy_from_user((void*)input.opaque, &buffer_len);
+		if (IS_ERR(data))
+			break;
+
+		export = data;
+		ret = psp_platform_pdh_cert_export(export, &input.psp_ret);
+		break;
+	}
+	default:
+		ret = -EINVAL;
+	}
+
+	if (data && psp_copy_to_user((void *)input.opaque,
+				data, buffer_len))
+		ret = -EFAULT;
+
+	if (copy_to_user(argp, &input, sizeof(struct psp_issue_cmd)))
+		ret = -EFAULT;
+
+	return ret;
+}
+
+static const struct file_operations fops = {
+	.owner = THIS_MODULE,
+	.unlocked_ioctl = psp_ioctl,
+};
+
+int psp_ops_init(struct psp_device *psp)
+{
+	struct miscdevice *misc = &psp->misc;
+
+	misc->minor = MISC_DYNAMIC_MINOR;
+	misc->name = psp->name;
+	misc->fops = &fops;
+
+	return misc_register(misc);
+}
+
+void psp_ops_exit(struct psp_device *psp)
+{
+	misc_deregister(&psp->misc);
+}
diff --git a/drivers/crypto/psp/psp-pci.c b/drivers/crypto/psp/psp-pci.c
new file mode 100644
index 0000000..2b4c379
--- /dev/null
+++ b/drivers/crypto/psp/psp-pci.c
@@ -0,0 +1,376 @@
+/*
+ * AMD Cryptographic Coprocessor (CCP) driver
+ *
+ * Copyright (C) 2016 Advanced Micro Devices, Inc.
+ *
+ * Author: Tom Lendacky <thomas.lendacky@amd.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+#include <linux/dma-mapping.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+
+#include "psp-dev.h"
+
+#define IO_BAR				2
+#define IO_OFFSET			0x10500
+
+#define MSIX_VECTORS			2
+
+struct psp_msix {
+	u32 vector;
+	char name[16];
+};
+
+struct psp_pci {
+	struct pci_dev *pdev;
+	int msix_count;
+	struct psp_msix msix[MSIX_VECTORS];
+};
+
+static int psp_get_msix_irqs(struct psp_device *psp)
+{
+	struct psp_pci *psp_pci = psp->dev_specific;
+	struct device *dev = psp->dev;
+	struct pci_dev *pdev = container_of(dev, struct pci_dev, dev);
+	struct msix_entry msix_entry[MSIX_VECTORS];
+	unsigned int name_len = sizeof(psp_pci->msix[0].name) - 1;
+	int v, ret;
+
+	for (v = 0; v < ARRAY_SIZE(msix_entry); v++)
+		msix_entry[v].entry = v;
+
+	ret = pci_enable_msix_range(pdev, msix_entry, 1, v);
+	if (ret < 0)
+		return ret;
+
+	psp_pci->msix_count = ret;
+	for (v = 0; v < psp_pci->msix_count; v++) {
+		/* Set the interrupt names and request the irqs */
+		snprintf(psp_pci->msix[v].name, name_len, "%s-%u", psp->name, v);
+		psp_pci->msix[v].vector = msix_entry[v].vector;
+		ret = request_irq(psp_pci->msix[v].vector, psp_irq_handler,
+				  0, psp_pci->msix[v].name, dev);
+		if (ret) {
+			dev_notice(dev, "unable to allocate MSI-X IRQ (%d)\n",
+				   ret);
+			goto e_irq;
+		}
+	}
+
+	return 0;
+
+e_irq:
+	while (v--)
+		free_irq(psp_pci->msix[v].vector, dev);
+	pci_disable_msix(pdev);
+	psp_pci->msix_count = 0;
+
+	return ret;
+}
+
+static int psp_get_msi_irq(struct psp_device *psp)
+{
+	struct device *dev = psp->dev;
+	struct pci_dev *pdev = container_of(dev, struct pci_dev, dev);
+	int ret;
+
+	ret = pci_enable_msi(pdev);
+	if (ret)
+		return ret;
+
+	psp->irq = pdev->irq;
+	ret = request_irq(psp->irq, psp_irq_handler, 0, psp->name, dev);
+	if (ret) {
+		dev_notice(dev, "unable to allocate MSI IRQ (%d)\n", ret);
+		goto e_msi;
+	}
+
+	return 0;
+
+e_msi:
+	pci_disable_msi(pdev);
+
+	return ret;
+}
+
+static int psp_get_irqs(struct psp_device *psp)
+{
+	struct device *dev = psp->dev;
+	int ret;
+
+	ret = psp_get_msix_irqs(psp);
+	if (!ret)
+		return 0;
+
+	/* Couldn't get MSI-X vectors, try MSI */
+	dev_notice(dev, "could not enable MSI-X (%d), trying MSI\n", ret);
+	ret = psp_get_msi_irq(psp);
+	if (!ret)
+		return 0;
+
+	/* Couldn't get MSI interrupt */
+	dev_notice(dev, "could not enable MSI (%d), trying PCI\n", ret);
+
+	return ret;
+}
+
+void psp_free_irqs(struct psp_device *psp)
+{
+	struct psp_pci *psp_pci = psp->dev_specific;
+	struct device *dev = psp->dev;
+	struct pci_dev *pdev = container_of(dev, struct pci_dev, dev);
+
+	if (psp_pci->msix_count) {
+		while (psp_pci->msix_count--)
+			free_irq(psp_pci->msix[psp_pci->msix_count].vector,
+				 dev);
+		pci_disable_msix(pdev);
+	} else {
+		free_irq(psp->irq, dev);
+		pci_disable_msi(pdev);
+	}
+}
+
+static bool psp_is_master(struct psp_device *cur, struct psp_device *new)
+{
+	struct psp_pci *psp_pci_cur, *psp_pci_new;
+	struct pci_dev *pdev_cur, *pdev_new;
+
+	psp_pci_cur = cur->dev_specific;
+	psp_pci_new = new->dev_specific;
+
+	pdev_cur = psp_pci_cur->pdev;
+	pdev_new = psp_pci_new->pdev;
+
+	if (pdev_new->bus->number < pdev_cur->bus->number)
+		return true;
+
+	if (PCI_SLOT(pdev_new->devfn) < PCI_SLOT(pdev_cur->devfn))
+		return true;
+
+	if (PCI_FUNC(pdev_new->devfn) < PCI_FUNC(pdev_cur->devfn))
+		return true;
+
+	return false;
+}
+
+static struct psp_device *psp_get_master(struct list_head *list)
+{
+	struct psp_device *psp, *tmp;
+
+	psp = NULL;
+	list_for_each_entry(tmp, list, entry) {
+		if (!psp || psp_is_master(psp, tmp))
+			psp = tmp;
+	}
+
+	return psp;
+}
+
+static int psp_find_mmio_area(struct psp_device *psp)
+{
+	struct device *dev = psp->dev;
+	struct pci_dev *pdev = container_of(dev, struct pci_dev, dev);
+	unsigned long io_flags;
+
+	io_flags = pci_resource_flags(pdev, IO_BAR);
+	if (io_flags & IORESOURCE_MEM)
+		return IO_BAR;
+
+	return -EIO;
+}
+
+static int psp_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+	struct psp_device *psp;
+	struct psp_pci *psp_pci;
+	struct device *dev = &pdev->dev;
+	unsigned int bar;
+	int ret;
+
+	ret = -ENOMEM;
+	psp = psp_alloc_struct(dev);
+	if (!psp)
+		goto e_err;
+
+	psp_pci = devm_kzalloc(dev, sizeof(*psp_pci), GFP_KERNEL);
+	if (!psp_pci) {
+		ret = -ENOMEM;
+		goto e_err;
+	}
+	psp_pci->pdev = pdev;
+	psp->dev_specific = psp_pci;
+	psp->get_irq = psp_get_irqs;
+	psp->free_irq = psp_free_irqs;
+	psp->get_master = psp_get_master;
+
+	ret = pci_request_regions(pdev, PSP_DRIVER_NAME);
+	if (ret) {
+		dev_err(dev, "pci_request_regions failed (%d)\n", ret);
+		goto e_err;
+	}
+
+	ret = pci_enable_device(pdev);
+	if (ret) {
+		dev_err(dev, "pci_enable_device failed (%d)\n", ret);
+		goto e_regions;
+	}
+
+	pci_set_master(pdev);
+
+	ret = psp_find_mmio_area(psp);
+	if (ret < 0)
+		goto e_device;
+	bar = ret;
+
+	ret = -EIO;
+	psp->io_map = pci_iomap(pdev, bar, 0);
+	if (!psp->io_map) {
+		dev_err(dev, "pci_iomap failed\n");
+		goto e_device;
+	}
+	psp->io_regs = psp->io_map + IO_OFFSET;
+
+	ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(48));
+	if (ret) {
+		ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
+		if (ret) {
+			dev_err(dev, "dma_set_mask_and_coherent failed (%d)\n",
+				ret);
+			goto e_iomap;
+		}
+	}
+
+	dev_set_drvdata(dev, psp);
+
+	ret = psp_init(psp);
+	if (ret)
+		goto e_iomap;
+
+	dev_notice(dev, "enabled\n");
+
+	return 0;
+
+e_iomap:
+	pci_iounmap(pdev, psp->io_map);
+
+e_device:
+	pci_disable_device(pdev);
+
+e_regions:
+	pci_release_regions(pdev);
+
+e_err:
+	dev_notice(dev, "initialization failed\n");
+	return ret;
+}
+
+static void psp_pci_remove(struct pci_dev *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct psp_device *psp = dev_get_drvdata(dev);
+
+	if (!psp)
+		return;
+
+	psp_destroy(psp);
+
+	pci_iounmap(pdev, psp->io_map);
+
+	pci_disable_device(pdev);
+
+	pci_release_regions(pdev);
+
+	dev_notice(dev, "disabled\n");
+}
+
+#if 0
+#ifdef CONFIG_PM
+static int ccp_pci_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+	struct device *dev = &pdev->dev;
+	struct ccp_device *ccp = dev_get_drvdata(dev);
+	unsigned long flags;
+	unsigned int i;
+
+	spin_lock_irqsave(&ccp->cmd_lock, flags);
+
+	ccp->suspending = 1;
+
+	/* Wake all the queue kthreads to prepare for suspend */
+	for (i = 0; i < ccp->cmd_q_count; i++)
+		wake_up_process(ccp->cmd_q[i].kthread);
+
+	spin_unlock_irqrestore(&ccp->cmd_lock, flags);
+
+	/* Wait for all queue kthreads to say they're done */
+	while (!ccp_queues_suspended(ccp))
+		wait_event_interruptible(ccp->suspend_queue,
+					 ccp_queues_suspended(ccp));
+
+	return 0;
+}
+
+static int ccp_pci_resume(struct pci_dev *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct ccp_device *ccp = dev_get_drvdata(dev);
+	unsigned long flags;
+	unsigned int i;
+
+	spin_lock_irqsave(&ccp->cmd_lock, flags);
+
+	ccp->suspending = 0;
+
+	/* Wake up all the kthreads */
+	for (i = 0; i < ccp->cmd_q_count; i++) {
+		ccp->cmd_q[i].suspended = 0;
+		wake_up_process(ccp->cmd_q[i].kthread);
+	}
+
+	spin_unlock_irqrestore(&ccp->cmd_lock, flags);
+
+	return 0;
+}
+#endif
+#endif
+
+static const struct pci_device_id psp_pci_table[] = {
+	{ PCI_VDEVICE(AMD, 0x1456), },
+	/* Last entry must be zero */
+	{ 0, }
+};
+MODULE_DEVICE_TABLE(pci, psp_pci_table);
+
+static struct pci_driver psp_pci_driver = {
+	.name = PSP_DRIVER_NAME,
+	.id_table = psp_pci_table,
+	.probe = psp_pci_probe,
+	.remove = psp_pci_remove,
+#if 0
+#ifdef CONFIG_PM
+	.suspend = ccp_pci_suspend,
+	.resume = ccp_pci_resume,
+#endif
+#endif
+};
+
+int psp_pci_init(void)
+{
+	return pci_register_driver(&psp_pci_driver);
+}
+
+void psp_pci_exit(void)
+{
+	pci_unregister_driver(&psp_pci_driver);
+}
diff --git a/include/linux/ccp-psp.h b/include/linux/ccp-psp.h
new file mode 100644
index 0000000..b5e791c
--- /dev/null
+++ b/include/linux/ccp-psp.h
@@ -0,0 +1,833 @@
+/*
+ * AMD Secure Processor (PSP) driver
+ *
+ * Copyright (C) 2016 Advanced Micro Devices, Inc.
+ *
+ * Author: Tom Lendacky <thomas.lendacky@amd.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __CPP_PSP_H__
+#define __CPP_PSP_H__
+
+#include <uapi/linux/ccp-psp.h>
+
+#ifdef CONFIG_X86
+#include <asm/mem_encrypt.h>
+
+#define __psp_pa(x)	__sme_pa(x)
+#else
+#define __psp_pa(x)	__pa(x)
+#endif
+
+/**
+ * struct psp_data_activate - PSP ACTIVATE command parameters
+ * @hdr: command header
+ * @handle: handle of the VM to activate
+ * @asid: asid assigned to the VM
+ */
+struct __attribute__ ((__packed__)) psp_data_activate {
+	struct psp_data_header hdr;		/* In/Out */
+	u32 handle;				/* In */
+	u32 asid;				/* In */
+};
+
+/**
+ * struct psp_data_deactivate - PSP DEACTIVATE command parameters
+ * @hdr: command header
+ * @handle: handle of the VM to deactivate
+ */
+struct __attribute__ ((__packed__)) psp_data_deactivate {
+	struct psp_data_header hdr;		/* In/Out */
+	u32 handle;				/* In */
+};
+
+/**
+ * struct psp_data_launch_start - PSP LAUNCH_START command parameters
+ * @hdr: command header
+ * @handle: handle assigned to the VM
+ * @flags: configuration flags for the VM
+ * @policy: policy information for the VM
+ * @dh_pub_qx: the Qx parameter of the VM owners ECDH public key
+ * @dh_pub_qy: the Qy parameter of the VM owners ECDH public key
+ * @nonce: nonce generated by the VM owner
+ */
+struct __attribute__ ((__packed__)) psp_data_launch_start {
+	struct psp_data_header hdr;
+	u32 handle;				/* In/Out */
+	u32 flags;				/* In */
+	u32 policy;				/* In */
+	u8  dh_pub_qx[32];			/* In */
+	u8  dh_pub_qy[32];			/* In */
+	u8  nonce[16];				/* In */
+};
+
+/**
+ * struct psp_data_launch_update - PSP LAUNCH_UPDATE command parameters
+ * @hdr: command header
+ * @handle: handle of the VM to update
+ * @length: length of memory to be encrypted
+ * @address: physical address of memory region to encrypt
+ */
+struct __attribute__ ((__packed__)) psp_data_launch_update {
+	struct psp_data_header hdr;		/* In/Out */
+	u32 handle;				/* In */
+	u64 address;				/* In */
+	u32 length;				/* In */
+};
+
+/**
+ * struct psp_data_launch_vcpus - PSP LAUNCH_FINISH VCPU state information
+ * @state_length: length of the VCPU state information to measure
+ * @state_mask_addr: mask of the bytes within the VCPU state information
+ *                   to use in the measurment
+ * @state_count: number of VCPUs to measure
+ * @state_addr: physical address of the VCPU state (VMCB)
+ */
+struct __attribute__ ((__packed__)) psp_data_launch_vcpus {
+	u32 state_length;			/* In */
+	u64 state_mask_addr;			/* In */
+	u32 state_count;			/* In */
+	u64 state_addr[];			/* In */
+};
+
+/**
+ * struct psp_data_launch_finish - PSP LAUNCH_FINISH command parameters
+ * @hdr: command header
+ * @handle: handle of the VM to process
+ * @measurement: the measurement of the encrypted VM memory areas
+ * @vcpus: the VCPU state information to include in the measurement
+ */
+struct __attribute__ ((__packed__)) psp_data_launch_finish {
+	struct psp_data_header hdr;		/* In/Out */
+	u32 handle;				/* In */
+	u8  measurement[32];			/* In/Out */
+	struct psp_data_launch_vcpus vcpus;	/* In */
+};
+
+/**
+ * struct psp_data_decommission - PSP DECOMMISSION command parameters
+ * @hdr: command header
+ * @handle: handle of the VM to decommission
+ */
+struct __attribute__ ((__packed__)) psp_data_decommission {
+	struct psp_data_header hdr;		/* In/Out */
+	u32 handle;				/* In */
+};
+
+/**
+ * struct psp_data_guest_status - PSP GUEST_STATUS command parameters
+ * @hdr: command header
+ * @handle: handle of the VM to retrieve status
+ * @policy: policy information for the VM
+ * @asid: current ASID of the VM
+ * @state: current state of the VM
+ */
+struct __attribute__ ((__packed__)) psp_data_guest_status {
+	struct psp_data_header hdr;		/* In/Out */
+	u32 handle;				/* In */
+	u32 policy;				/* Out */
+	u32 asid;				/* Out */
+	u8 state;				/* Out */
+};
+
+/**
+ * struct psp_data_dbg - PSP DBG_ENCRYPT/DBG_DECRYPT command parameters
+ * @hdr: command header
+ * @handle: handle of the VM to perform debug operation
+ * @src_addr: source address of data to operate on
+ * @dst_addr: destination address of data to operate on
+ * @length: length of data to operate on
+ */
+struct __attribute__ ((__packed__)) psp_data_dbg {
+	struct psp_data_header hdr;		/* In/Out */
+	u32 handle;				/* In */
+	u64 src_addr;				/* In */
+	u64 dst_addr;				/* In */
+	u32 length;				/* In */
+};
+
+/**
+ * struct psp_data_receive_start - PSP RECEIVE_START command parameters
+ *
+ * @hdr: command header
+ * @handle: handle of the VM to receiving the guest
+ * @flags: flags for the receive process
+ * @policy: guest policy flags
+ * @policy_meas: HMAC of policy keypad
+ * @wrapped_tek: wrapped transport encryption key
+ * @wrapped_tik: wrapped transport integrity key
+ * @ten: transport encryption nonce
+ * @dh_pub_qx: qx parameter of the origin's ECDH public key
+ * @dh_pub_qy: qy parameter of the origin's ECDH public key
+ * @nonce: nonce generated by the origin
+ */
+struct __attribute__((__packed__)) psp_data_receive_start {
+	struct psp_data_header hdr;	/* In/Out */
+	u32 handle;			/* In/Out */
+	u32 flags;			/* In */
+	u32 policy;			/* In */
+	u8 policy_meas[32];		/* In */
+	u8 wrapped_tek[24];		/* In */
+	u8 reserved1[8];
+	u8 wrapped_tik[24];		/* In */
+	u8 reserved2[8];
+	u8 ten[16];			/* In */
+	u8 dh_pub_qx[32];		/* In */
+	u8 dh_pub_qy[32];		/* In */
+	u8 nonce[16];			/* In */
+};
+
+/**
+ * struct psp_receive_update - PSP RECEIVE_UPDATE command parameters
+ *
+ * @hdr: command header
+ * @handle: handle of the VM to receiving the guest
+ * @iv: initialization vector for this blob of memory
+ * @count: number of memory areas to be encrypted
+ * @length: length of memory to be encrypted
+ * @address: physical address of memory region to encrypt
+ */
+struct __attribute__((__packed__)) psp_data_receive_update {
+	struct psp_data_header hdr;		/* In/Out */
+	u32 handle;				/* In */
+	u8 iv[16];				/* In */
+	u64 address;				/* In */
+	u32 length;				/* In */
+};
+
+/**
+ * struct psp_data_receive_finish - PSP RECEIVE_FINISH command parameters
+ * @hdr: command header
+ * @handle: handle of the VM to process
+ * @measurement: the measurement of the transported guest
+ */
+struct __attribute__ ((__packed__)) psp_data_receive_finish {
+	struct psp_data_header hdr;		/* In/Out */
+	u32 handle;				/* In */
+	u8  measurement[32];			/* In */
+};
+
+/**
+ * struct psp_data_send_start - PSP SEND_START command parameters
+ * @hdr: command header
+ * @nonce: nonce generated by firmware
+ * @policy: guest policy flags
+ * @policy_meas: HMAC of policy keyed with TIK
+ * @wrapped_tek: wrapped transport encryption key
+ * @wrapped_tik: wrapped transport integrity key
+ * @ten: transport encryrption nonce
+ * @iv: the IV of transport encryption block
+ * @handle: handle of the VM to process
+ * @flags: flags for send command
+ * @major: API major number
+ * @minor: API minor number
+ * @serial: platform serial number
+ * @dh_pub_qx: the Qx parameter of the target DH public key
+ * @dh_pub_qy: the Qy parameter of the target DH public key
+ * @pek_sig_r: the r component of the PEK signature
+ * @pek_sig_s: the s component of the PEK signature
+ * @cek_sig_r: the r component of the CEK signature
+ * @cek_sig_s: the s component of the CEK signature
+ * @cek_pub_qx: the Qx parameter of the CEK public key
+ * @cek_pub_qy: the Qy parameter of the CEK public key
+ * @ask_sig_r: the r component of the ASK signature
+ * @ask_sig_s: the s component of the ASK signature
+ * @ncerts: number of certificates in certificate chain
+ * @cert_len: length of certificates
+ * @certs: certificate in chain
+ */
+
+struct __attribute__((__packed__)) psp_data_send_start {
+	struct psp_data_header hdr;			/* In/Out */
+	u8 nonce[16];					/* Out */
+	u32 policy;					/* Out */
+	u8 policy_meas[32];				/* Out */
+	u8 wrapped_tek[24];				/* Out */
+	u8 reserved1[8];
+	u8 wrapped_tik[24];				/* Out */
+	u8 reserved2[8];
+	u8 ten[16];					/* Out */
+	u8 iv[16];					/* Out */
+	u32 handle;					/* In */
+	u32 flags;					/* In */
+	u8 api_major;					/* In */
+	u8 api_minor;					/* In */
+	u8 reserved3[2];
+	u32 serial;					/* In */
+	u8 dh_pub_qx[32];				/* In */
+	u8 dh_pub_qy[32];				/* In */
+	u8 pek_sig_r[32];				/* In */
+	u8 pek_sig_s[32];				/* In */
+	u8 cek_sig_r[32];				/* In */
+	u8 cek_sig_s[32];				/* In */
+	u8 cek_pub_qx[32];				/* In */
+	u8 cek_pub_qy[32];				/* In */
+	u8 ask_sig_r[32];				/* In */
+	u8 ask_sig_s[32];				/* In */
+	u32 ncerts;					/* In */
+	u32 cert_length;				/* In */
+	u8 certs[];					/* In */
+};
+
+/**
+ * struct psp_data_send_update - PSP SEND_UPDATE command parameters
+ *
+ * @hdr: command header
+ * @handle: handle of the VM to receiving the guest
+ * @len: length of memory region to encrypt
+ * @src_addr: physical address of memory region to encrypt from
+ * @dst_addr: physical address of memory region to encrypt to
+ */
+struct __attribute__((__packed__)) psp_data_send_update {
+	struct psp_data_header hdr;		/* In/Out */
+	u32 handle;				/* In */
+	u64 src_addr;				/* In */
+	u64 dst_addr;				/* In */
+	u32 length;				/* In */
+};
+
+/**
+ * struct psp_data_send_finish - PSP SEND_FINISH command parameters
+ * @hdr: command header
+ * @handle: handle of the VM to process
+ * @measurement: the measurement of the transported guest
+ */
+struct __attribute__ ((__packed__)) psp_data_send_finish {
+	struct psp_data_header hdr;		/* In/Out */
+	u32 handle;				/* In */
+	u8  measurement[32];			/* Out */
+};
+
+#if defined(CONFIG_CRYPTO_DEV_PSP_DD) || \
+	defined(CONFIG_CRYPTO_DEV_PSP_DD_MODULE)
+
+/**
+ * psp_platform_init - perform PSP INIT command
+ *
+ * @init: psp_data_init structure to be processed
+ * @psp_ret: PSP command return code
+ *
+ * Returns:
+ * 0 if the PSP successfully processed the command
+ * -%ENODEV    if the PSP device is not available
+ * -%ENOTSUPP  if the PSP does not support SEV
+ * -%ETIMEDOUT if the PSP command timed out
+ * -%EIO       if the PSP returned a non-zero return code
+ */
+int psp_platform_init(struct psp_data_init *init, int *psp_ret);
+
+/**
+ * psp_platform_shutdown - perform PSP SHUTDOWN command
+ *
+ * @psp_ret: PSP command return code
+ *
+ * Returns:
+ * 0 if the PSP successfully processed the command
+ * -%ENODEV    if the PSP device is not available
+ * -%ENOTSUPP  if the PSP does not support SEV
+ * -%ETIMEDOUT if the PSP command timed out
+ * -%EIO       if the PSP returned a non-zero return code
+ */
+int psp_platform_shutdown(int *psp_ret);
+
+/**
+ * psp_platform_status - perform PSP PLATFORM_STATUS command
+ *
+ * @init: psp_data_status structure to be processed
+ * @psp_ret: PSP command return code
+ *
+ * Returns:
+ * 0 if the PSP successfully processed the command
+ * -%ENODEV    if the PSP device is not available
+ * -%ENOTSUPP  if the PSP does not support SEV
+ * -%ETIMEDOUT if the PSP command timed out
+ * -%EIO       if the PSP returned a non-zero return code
+ */
+int psp_platform_status(struct psp_data_status *status, int *psp_ret);
+
+/**
+ * psp_guest_launch_start - perform PSP LAUNCH_START command
+ *
+ * @start: psp_data_launch_start structure to be processed
+ * @psp_ret: PSP command return code
+ *
+ * Returns:
+ * 0 if the PSP successfully processed the command
+ * -%ENODEV    if the PSP device is not available
+ * -%ENOTSUPP  if the PSP does not support SEV
+ * -%ETIMEDOUT if the PSP command timed out
+ * -%EIO       if the PSP returned a non-zero return code
+ */
+int psp_guest_launch_start(struct psp_data_launch_start *start, int *psp_ret);
+
+/**
+ * psp_guest_launch_update - perform PSP LAUNCH_UPDATE command
+ *
+ * @update: psp_data_launch_update structure to be processed
+ * @timeout: command timeout
+ * @psp_ret: PSP command return code
+ *
+ * Returns:
+ * 0 if the PSP successfully processed the command
+ * -%ENODEV    if the PSP device is not available
+ * -%ENOTSUPP  if the PSP does not support SEV
+ * -%ETIMEDOUT if the PSP command timed out
+ * -%EIO       if the PSP returned a non-zero return code
+ */
+int psp_guest_launch_update(struct psp_data_launch_update *update,
+			    unsigned int timeout, int *psp_ret);
+
+/**
+ * psp_guest_launch_finish - perform PSP LAUNCH_FINISH command
+ *
+ * @finish: psp_data_launch_finish structure to be processed
+ * @psp_ret: PSP command return code
+ *
+ * Returns:
+ * 0 if the PSP successfully processed the command
+ * -%ENODEV    if the PSP device is not available
+ * -%ENOTSUPP  if the PSP does not support SEV
+ * -%ETIMEDOUT if the PSP command timed out
+ * -%EIO       if the PSP returned a non-zero return code
+ */
+int psp_guest_launch_finish(struct psp_data_launch_finish *finish, int *psp_ret);
+
+/**
+ * psp_guest_activate - perform PSP ACTIVATE command
+ *
+ * @activate: psp_data_activate structure to be processed
+ * @psp_ret: PSP command return code
+ *
+ * Returns:
+ * 0 if the PSP successfully processed the command
+ * -%ENODEV    if the PSP device is not available
+ * -%ENOTSUPP  if the PSP does not support SEV
+ * -%ETIMEDOUT if the PSP command timed out
+ * -%EIO       if the PSP returned a non-zero return code
+ */
+int psp_guest_activate(struct psp_data_activate *activate, int *psp_ret);
+
+/**
+ * psp_guest_deactivate - perform PSP DEACTIVATE command
+ *
+ * @deactivate: psp_data_deactivate structure to be processed
+ * @psp_ret: PSP command return code
+ *
+ * Returns:
+ * 0 if the PSP successfully processed the command
+ * -%ENODEV    if the PSP device is not available
+ * -%ENOTSUPP  if the PSP does not support SEV
+ * -%ETIMEDOUT if the PSP command timed out
+ * -%EIO       if the PSP returned a non-zero return code
+ */
+int psp_guest_deactivate(struct psp_data_deactivate *deactivate, int *psp_ret);
+
+/**
+ * psp_guest_df_flush - perform PSP DF_FLUSH command
+ *
+ * @psp_ret: PSP command return code
+ *
+ * Returns:
+ * 0 if the PSP successfully processed the command
+ * -%ENODEV    if the PSP device is not available
+ * -%ENOTSUPP  if the PSP does not support SEV
+ * -%ETIMEDOUT if the PSP command timed out
+ * -%EIO       if the PSP returned a non-zero return code
+ */
+int psp_guest_df_flush(int *psp_ret);
+
+/**
+ * psp_guest_decommission - perform PSP DECOMMISSION command
+ *
+ * @decommission: psp_data_decommission structure to be processed
+ * @psp_ret: PSP command return code
+ *
+ * Returns:
+ * 0 if the PSP successfully processed the command
+ * -%ENODEV    if the PSP device is not available
+ * -%ENOTSUPP  if the PSP does not support SEV
+ * -%ETIMEDOUT if the PSP command timed out
+ * -%EIO       if the PSP returned a non-zero return code
+ */
+int psp_guest_decommission(struct psp_data_decommission *decommission,
+			   int *psp_ret);
+
+/**
+ * psp_guest_status - perform PSP GUEST_STATUS command
+ *
+ * @status: psp_data_guest_status structure to be processed
+ * @psp_ret: PSP command return code
+ *
+ * Returns:
+ * 0 if the PSP successfully processed the command
+ * -%ENODEV    if the PSP device is not available
+ * -%ENOTSUPP  if the PSP does not support SEV
+ * -%ETIMEDOUT if the PSP command timed out
+ * -%EIO       if the PSP returned a non-zero return code
+ */
+int psp_guest_status(struct psp_data_guest_status *status, int *psp_ret);
+
+/**
+ * psp_dbg_decrypt - perform PSP DBG_DECRYPT command
+ *
+ * @dbg: psp_data_dbg structure to be processed
+ * @psp_ret: PSP command return code
+ *
+ * Returns:
+ * 0 if the PSP successfully processed the command
+ * -%ENODEV    if the PSP device is not available
+ * -%ENOTSUPP  if the PSP does not support SEV
+ * -%ETIMEDOUT if the PSP command timed out
+ * -%EIO       if the PSP returned a non-zero return code
+ */
+int psp_dbg_decrypt(struct psp_data_dbg *dbg, int *psp_ret);
+
+/**
+ * psp_dbg_encrypt - perform PSP DBG_ENCRYPT command
+ *
+ * @dbg: psp_data_dbg structure to be processed
+ * @psp_ret: PSP command return code
+ *
+ * Returns:
+ * 0 if the PSP successfully processed the command
+ * -%ENODEV    if the PSP device is not available
+ * -%ENOTSUPP  if the PSP does not support SEV
+ * -%ETIMEDOUT if the PSP command timed out
+ * -%EIO       if the PSP returned a non-zero return code
+ */
+int psp_dbg_encrypt(struct psp_data_dbg *dbg, int *psp_ret);
+
+/**
+ * psp_guest_receive_start - perform PSP RECEIVE_START command
+ *
+ * @start: psp_data_receive_start structure to be processed
+ * @psp_ret: PSP command return code
+ *
+ * Returns:
+ * 0 if the PSP successfully processed the command
+ * -%ENODEV    if the PSP device is not available
+ * -%ENOTSUPP  if the PSP does not support SEV
+ * -%ETIMEDOUT if the PSP command timed out
+ * -%EIO       if the PSP returned a non-zero return code
+ */
+int psp_guest_receive_start(struct psp_data_receive_start *start, int *psp_ret);
+
+/**
+ * psp_guest_receive_update - perform PSP RECEIVE_UPDATE command
+ *
+ * @update: psp_data_receive_update structure to be processed
+ * @timeout: command timeout
+ * @psp_ret: PSP command return code
+ *
+ * Returns:
+ * 0 if the PSP successfully processed the command
+ * -%ENODEV    if the PSP device is not available
+ * -%ENOTSUPP  if the PSP does not support SEV
+ * -%ETIMEDOUT if the PSP command timed out
+ * -%EIO       if the PSP returned a non-zero return code
+ */
+int psp_guest_receive_update(struct psp_data_receive_update *update,
+			    unsigned int timeout, int *psp_ret);
+
+/**
+ * psp_guest_receive_finish - perform PSP RECEIVE_FINISH command
+ *
+ * @finish: psp_data_receive_finish structure to be processed
+ * @psp_ret: PSP command return code
+ *
+ * Returns:
+ * 0 if the PSP successfully processed the command
+ * -%ENODEV    if the PSP device is not available
+ * -%ENOTSUPP  if the PSP does not support SEV
+ * -%ETIMEDOUT if the PSP command timed out
+ * -%EIO       if the PSP returned a non-zero return code
+ */
+int psp_guest_receive_finish(struct psp_data_receive_finish *finish,
+			     int *psp_ret);
+
+/**
+ * psp_guest_send_start - perform PSP RECEIVE_START command
+ *
+ * @start: psp_data_send_start structure to be processed
+ * @psp_ret: PSP command return code
+ *
+ * Returns:
+ * 0 if the PSP successfully processed the command
+ * -%ENODEV    if the PSP device is not available
+ * -%ENOTSUPP  if the PSP does not support SEV
+ * -%ETIMEDOUT if the PSP command timed out
+ * -%EIO       if the PSP returned a non-zero return code
+ */
+int psp_guest_send_start(struct psp_data_send_start *start, int *psp_ret);
+
+/**
+ * psp_guest_send_update - perform PSP RECEIVE_UPDATE command
+ *
+ * @update: psp_data_send_update structure to be processed
+ * @timeout: command timeout
+ * @psp_ret: PSP command return code
+ *
+ * Returns:
+ * 0 if the PSP successfully processed the command
+ * -%ENODEV    if the PSP device is not available
+ * -%ENOTSUPP  if the PSP does not support SEV
+ * -%ETIMEDOUT if the PSP command timed out
+ * -%EIO       if the PSP returned a non-zero return code
+ */
+int psp_guest_send_update(struct psp_data_send_update *update,
+			    unsigned int timeout, int *psp_ret);
+
+/**
+ * psp_guest_send_finish - perform PSP RECEIVE_FINISH command
+ *
+ * @finish: psp_data_send_finish structure to be processed
+ * @psp_ret: PSP command return code
+ *
+ * Returns:
+ * 0 if the PSP successfully processed the command
+ * -%ENODEV    if the PSP device is not available
+ * -%ENOTSUPP  if the PSP does not support SEV
+ * -%ETIMEDOUT if the PSP command timed out
+ * -%EIO       if the PSP returned a non-zero return code
+ */
+int psp_guest_send_finish(struct psp_data_send_finish *finish,
+			     int *psp_ret);
+
+/**
+ * psp_platform_pdh_gen - perform PSP PDH_GEN command
+ *
+ * @psp_ret: PSP command return code
+ *
+ * Returns:
+ * 0 if the PSP successfully processed the command
+ * -%ENODEV    if the PSP device is not available
+ * -%ENOTSUPP  if the PSP does not support SEV
+ * -%ETIMEDOUT if the PSP command timed out
+ * -%EIO       if the PSP returned a non-zero return code
+ */
+int psp_platform_pdh_gen(int *psp_ret);
+
+/**
+ * psp_platform_pdh_cert_export - perform PSP PDH_CERT_EXPORT command
+ *
+ * @data: psp_data_platform_pdh_cert_export structure to be processed
+ * @psp_ret: PSP command return code
+ *
+ * Returns:
+ * 0 if the PSP successfully processed the command
+ * -%ENODEV    if the PSP device is not available
+ * -%ENOTSUPP  if the PSP does not support SEV
+ * -%ETIMEDOUT if the PSP command timed out
+ * -%EIO       if the PSP returned a non-zero return code
+ */
+int psp_platform_pdh_cert_export(struct psp_data_pdh_cert_export *data,
+				int *psp_ret);
+
+/**
+ * psp_platform_pek_gen - perform PSP PEK_GEN command
+ *
+ * @psp_ret: PSP command return code
+ *
+ * Returns:
+ * 0 if the PSP successfully processed the command
+ * -%ENODEV    if the PSP device is not available
+ * -%ENOTSUPP  if the PSP does not support SEV
+ * -%ETIMEDOUT if the PSP command timed out
+ * -%EIO       if the PSP returned a non-zero return code
+ */
+int psp_platform_pek_gen(int *psp_ret);
+
+/**
+ * psp_platform_pek_cert_import - perform PSP PEK_CERT_IMPORT command
+ *
+ * @data: psp_data_platform_pek_cert_import structure to be processed
+ * @psp_ret: PSP command return code
+ *
+ * Returns:
+ * 0 if the PSP successfully processed the command
+ * -%ENODEV    if the PSP device is not available
+ * -%ENOTSUPP  if the PSP does not support SEV
+ * -%ETIMEDOUT if the PSP command timed out
+ * -%EIO       if the PSP returned a non-zero return code
+ */
+int psp_platform_pek_cert_import(struct psp_data_pek_cert_import *data,
+				int *psp_ret);
+
+/**
+ * psp_platform_pek_csr - perform PSP PEK_CSR command
+ *
+ * @data: psp_data_platform_pek_csr structure to be processed
+ * @psp_ret: PSP command return code
+ *
+ * Returns:
+ * 0 if the PSP successfully processed the command
+ * -%ENODEV    if the PSP device is not available
+ * -%ENOTSUPP  if the PSP does not support SEV
+ * -%ETIMEDOUT if the PSP command timed out
+ * -%EIO       if the PSP returned a non-zero return code
+ */
+int psp_platform_pek_csr(struct psp_data_pek_csr *data, int *psp_ret);
+
+/**
+ * psp_platform_factory_reset - perform PSP FACTORY_RESET command
+ *
+ * @psp_ret: PSP command return code
+ *
+ * Returns:
+ * 0 if the PSP successfully processed the command
+ * -%ENODEV    if the PSP device is not available
+ * -%ENOTSUPP  if the PSP does not support SEV
+ * -%ETIMEDOUT if the PSP command timed out
+ * -%EIO       if the PSP returned a non-zero return code
+ */
+int psp_platform_factory_reset(int *psp_ret);
+
+#else	/* CONFIG_CRYPTO_DEV_PSP_DD is not enabled */
+
+static inline int psp_platform_status(struct psp_data_status *status,
+				      int *psp_ret)
+{
+	return -ENODEV;
+}
+
+static inline int psp_platform_init(struct psp_data_init *init, int *psp_ret)
+{
+	return -ENODEV;
+}
+
+static inline int psp_platform_shutdown(int *psp_ret)
+{
+	return -ENODEV;
+}
+
+static inline int psp_guest_launch_start(struct psp_data_launch_start *start,
+					 int *psp_ret)
+{
+	return -ENODEV;
+}
+
+static inline int psp_guest_launch_update(struct psp_data_launch_update *update,
+					  unsigned int timeout, int *psp_ret)
+{
+	return -ENODEV;
+}
+
+static inline int psp_guest_launch_finish(struct psp_data_launch_finish *finish,
+					  int *psp_ret)
+{
+	return -ENODEV;
+}
+
+static inline int psp_guest_activate(struct psp_data_activate *activate,
+				     int *psp_ret)
+{
+	return -ENODEV;
+}
+
+static inline int psp_guest_deactivate(struct psp_data_deactivate *deactivate,
+				       int *psp_ret)
+{
+	return -ENODEV;
+}
+
+static inline int psp_guest_df_flush(int *psp_ret)
+{
+	return -ENODEV;
+}
+
+static inline int psp_guest_decommission(struct psp_data_decommission *decommission,
+					 int *psp_ret)
+{
+	return -ENODEV;
+}
+
+static inline int psp_guest_status(struct psp_data_guest_status *status,
+				   int *psp_ret)
+{
+	return -ENODEV;
+}
+
+static inline int psp_dbg_decrypt(struct psp_data_dbg *dbg, int *psp_ret)
+{
+	return -ENODEV;
+}
+
+static inline int psp_dbg_encrypt(struct psp_data_dbg *dbg, int *psp_ret)
+{
+	return -ENODEV;
+}
+
+static inline int psp_guest_receive_start(struct psp_data_receive_start *start,
+					 int *psp_ret)
+{
+	return -ENODEV;
+}
+
+static inline int psp_guest_receive_update(struct psp_data_receive_update *update,
+					  unsigned int timeout, int *psp_ret)
+{
+	return -ENODEV;
+}
+
+static inline int psp_guest_receive_finish(struct psp_data_receive_finish *finish,
+					  int *psp_ret)
+{
+	return -ENODEV;
+}
+static inline int psp_guest_send_start(struct psp_data_send_start *start,
+					 int *psp_ret)
+{
+	return -ENODEV;
+}
+
+static inline int psp_guest_send_update(struct psp_data_send_update *update,
+					  unsigned int timeout, int *psp_ret)
+{
+	return -ENODEV;
+}
+
+static inline int psp_guest_send_finish(struct psp_data_send_finish *finish,
+					  int *psp_ret)
+{
+	return -ENODEV;
+}
+
+static inline int psp_platform_pdh_gen(int *psp_ret)
+{
+	return -ENODEV;
+}
+
+int psp_platform_pdh_cert_export(struct psp_data_pdh_cert_export *data,
+				int *psp_ret)
+{
+	return -ENODEV;
+}
+
+static inline int psp_platform_pek_gen(int *psp_ret)
+{
+	return -ENODEV;
+}
+
+int psp_platform_pek_cert_import(struct psp_data_pek_cert_import *data,
+				int *psp_ret)
+{
+	return -ENODEV;
+}
+
+int psp_platform_pek_csr(struct psp_data_pek_csr *data, int *psp_ret)
+{
+	return -ENODEV;
+}
+
+static inline int psp_platform_factory_reset(int *psp_ret)
+{
+	return -ENODEV;
+}
+
+#endif	/* CONFIG_CRYPTO_DEV_PSP_DD */
+
+#endif	/* __CPP_PSP_H__ */
diff --git a/include/uapi/linux/Kbuild b/include/uapi/linux/Kbuild
index 185f8ea..af2511a 100644
--- a/include/uapi/linux/Kbuild
+++ b/include/uapi/linux/Kbuild
@@ -470,3 +470,4 @@ header-y += xilinx-v4l2-controls.h
 header-y += zorro.h
 header-y += zorro_ids.h
 header-y += userfaultfd.h
+header-y += ccp-psp.h
diff --git a/include/uapi/linux/ccp-psp.h b/include/uapi/linux/ccp-psp.h
new file mode 100644
index 0000000..e780b46
--- /dev/null
+++ b/include/uapi/linux/ccp-psp.h
@@ -0,0 +1,182 @@
+#ifndef _UAPI_LINUX_CCP_PSP_
+#define _UAPI_LINUX_CCP_PSP_
+
+/*
+ * Userspace interface to communicated with CCP-PSP driver.
+ */
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+
+/**
+ * struct psp_data_header - Common PSP communication header
+ * @buffer_len: length of the buffer supplied to the PSP
+ */
+
+struct __attribute__ ((__packed__)) psp_data_header {
+	__u32 buffer_len;				/* In/Out */
+};
+
+/**
+ * struct psp_data_init - PSP INIT command parameters
+ * @hdr: command header
+ * @flags: processing flags
+ */
+struct __attribute__ ((__packed__)) psp_data_init {
+	struct psp_data_header hdr;
+	__u32 flags;				/* In */
+};
+
+/**
+ * struct psp_data_status - PSP PLATFORM_STATUS command parameters
+ * @hdr: command header
+ * @major: major API version
+ * @minor: minor API version
+ * @state: platform state
+ * @cert_status: bit fields describing certificate status
+ * @flags: platform flags
+ * @guest_count: number of active guests
+ */
+struct __attribute__ ((__packed__)) psp_data_status {
+	struct psp_data_header hdr;
+	__u8 api_major;				/* Out */
+	__u8 api_minor;				/* Out */
+	__u8 state;				/* Out */
+	__u8 cert_status;			/* Out */
+	__u32 flags;				/* Out */
+	__u32 guest_count;			/* Out */
+};
+
+/**
+ * struct psp_data_pek_csr - PSP PEK_CSR command parameters
+ * @hdr: command header
+ * @csr - certificate signing request formatted with PKCS
+ */
+struct __attribute__((__packed__)) psp_data_pek_csr {
+	struct psp_data_header hdr;			/* In/Out */
+	__u8 csr[];					/* Out */
+};
+
+/**
+ * struct psp_data_cert_import - PSP PEK_CERT_IMPORT command parameters
+ * @hdr: command header
+ * @ncerts: number of certificates in the chain
+ * @cert_len: length of certificates
+ * @certs: certificate chain starting with PEK and end with CA certificate
+ */
+struct __attribute__((__packed__)) psp_data_pek_cert_import {
+	struct psp_data_header hdr;			/* In/Out */
+	__u32 ncerts;					/* In */
+	__u32 cert_len;					/* In */
+	__u8 certs[];					/* In */
+};
+
+/**
+ * struct psp_data_pdh_cert_export - PSP PDH_CERT_EXPORT command parameters
+ * @hdr: command header
+ * @major: API major number
+ * @minor: API minor number
+ * @serial: platform serial number
+ * @pdh_pub_qx: the Qx parameter of the target PDH public key
+ * @pdh_pub_qy: the Qy parameter of the target PDH public key
+ * @pek_sig_r: the r component of the PEK signature
+ * @pek_sig_s: the s component of the PEK signature
+ * @cek_sig_r: the r component of the CEK signature
+ * @cek_sig_s: the s component of the CEK signature
+ * @cek_pub_qx: the Qx parameter of the CEK public key
+ * @cek_pub_qy: the Qy parameter of the CEK public key
+ * @ncerts: number of certificates in certificate chain
+ * @cert_len: length of certificates
+ * @certs: certificate chain starting with PEK and end with CA certificate
+ */
+struct __attribute__((__packed__)) psp_data_pdh_cert_export {
+	struct psp_data_header hdr;			/* In/Out */
+	__u8 api_major;					/* Out */
+	__u8 api_minor;					/* Out */
+	__u8 reserved1[2];
+	__u32 serial;					/* Out */
+	__u8 pdh_pub_qx[32];				/* Out */
+	__u8 pdh_pub_qy[32];				/* Out */
+	__u8 pek_sig_r[32];				/* Out */
+	__u8 pek_sig_s[32];				/* Out */
+	__u8 cek_sig_r[32];				/* Out */
+	__u8 cek_sig_s[32];				/* Out */
+	__u8 cek_pub_qx[32];				/* Out */
+	__u8 cek_pub_qy[32];				/* Out */
+	__u32 ncerts;					/* Out */
+	__u32 cert_len;					/* Out */
+	__u8 certs[];					/* Out */
+};
+
+/**
+ * platform and management commands
+ */
+enum psp_cmd {
+	PSP_CMD_INIT = 1,
+	PSP_CMD_LAUNCH_START,
+	PSP_CMD_LAUNCH_UPDATE,
+	PSP_CMD_LAUNCH_FINISH,
+	PSP_CMD_ACTIVATE,
+	PSP_CMD_DF_FLUSH,
+	PSP_CMD_SHUTDOWN,
+	PSP_CMD_FACTORY_RESET,
+	PSP_CMD_PLATFORM_STATUS,
+	PSP_CMD_PEK_GEN,
+	PSP_CMD_PEK_CSR,
+	PSP_CMD_PEK_CERT_IMPORT,
+	PSP_CMD_PDH_GEN,
+	PSP_CMD_PDH_CERT_EXPORT,
+	PSP_CMD_SEND_START,
+	PSP_CMD_SEND_UPDATE,
+	PSP_CMD_SEND_FINISH,
+	PSP_CMD_RECEIVE_START,
+	PSP_CMD_RECEIVE_UPDATE,
+	PSP_CMD_RECEIVE_FINISH,
+	PSP_CMD_GUEST_STATUS,
+	PSP_CMD_DEACTIVATE,
+	PSP_CMD_DECOMMISSION,
+	PSP_CMD_DBG_DECRYPT,
+	PSP_CMD_DBG_ENCRYPT,
+	PSP_CMD_MAX,
+};
+
+/**
+ * status code returned by the commands
+ */
+enum psp_ret_code {
+	PSP_RET_SUCCESS = 0,
+	PSP_RET_INVALID_PLATFORM_STATE,
+	PSP_RET_INVALID_GUEST_STATE,
+	PSP_RET_INAVLID_CONFIG,
+	PSP_RET_CMDBUF_TOO_SMALL,
+	PSP_RET_ALREADY_OWNED,
+	PSP_RET_INVALID_CERTIFICATE,
+	PSP_RET_POLICY_FAILURE,
+	PSP_RET_INACTIVE,
+	PSP_RET_INVALID_ADDRESS,
+	PSP_RET_BAD_SIGNATURE,
+	PSP_RET_BAD_MEASUREMENT,
+	PSP_RET_ASID_OWNED,
+	PSP_RET_INVALID_ASID,
+	PSP_RET_WBINVD_REQUIRED,
+	PSP_RET_DFFLUSH_REQUIRED,
+	PSP_RET_INVALID_GUEST,
+};
+
+/**
+ * struct psp_issue_cmd - PSP ioctl parameters
+ * @cmd: PSP commands to execute
+ * @opaque: pointer to the command structure
+ * @psp_ret: PSP return code on failure
+ */
+struct psp_issue_cmd {
+	__u32 cmd;					/* In */
+	__u64 opaque;					/* In */
+	__u32 psp_ret;					/* Out */
+};
+
+#define PSP_IOC_TYPE		'P'
+#define PSP_ISSUE_CMD	_IOWR(PSP_IOC_TYPE, 0x0, struct psp_issue_cmd)
+
+#endif /* _UAPI_LINUX_CCP_PSP_H */
+
