|
@@ -0,0 +1,105 @@
|
|
|
+/*
|
|
|
+ * AMD Platform Security Processor (PSP) interface
|
|
|
+ *
|
|
|
+ * Copyright (C) 2016-2017 Advanced Micro Devices, Inc.
|
|
|
+ *
|
|
|
+ * Author: Brijesh Singh <brijesh.singh@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/kthread.h>
|
|
|
+#include <linux/sched.h>
|
|
|
+#include <linux/interrupt.h>
|
|
|
+#include <linux/spinlock.h>
|
|
|
+#include <linux/spinlock_types.h>
|
|
|
+#include <linux/types.h>
|
|
|
+#include <linux/mutex.h>
|
|
|
+#include <linux/delay.h>
|
|
|
+#include <linux/hw_random.h>
|
|
|
+#include <linux/ccp.h>
|
|
|
+
|
|
|
+#include "sp-dev.h"
|
|
|
+#include "psp-dev.h"
|
|
|
+
|
|
|
+static struct psp_device *psp_alloc_struct(struct sp_device *sp)
|
|
|
+{
|
|
|
+ struct device *dev = sp->dev;
|
|
|
+ struct psp_device *psp;
|
|
|
+
|
|
|
+ psp = devm_kzalloc(dev, sizeof(*psp), GFP_KERNEL);
|
|
|
+ if (!psp)
|
|
|
+ return NULL;
|
|
|
+
|
|
|
+ psp->dev = dev;
|
|
|
+ psp->sp = sp;
|
|
|
+
|
|
|
+ snprintf(psp->name, sizeof(psp->name), "psp-%u", sp->ord);
|
|
|
+
|
|
|
+ return psp;
|
|
|
+}
|
|
|
+
|
|
|
+static irqreturn_t psp_irq_handler(int irq, void *data)
|
|
|
+{
|
|
|
+ return IRQ_HANDLED;
|
|
|
+}
|
|
|
+
|
|
|
+int psp_dev_init(struct sp_device *sp)
|
|
|
+{
|
|
|
+ struct device *dev = sp->dev;
|
|
|
+ struct psp_device *psp;
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ ret = -ENOMEM;
|
|
|
+ psp = psp_alloc_struct(sp);
|
|
|
+ if (!psp)
|
|
|
+ goto e_err;
|
|
|
+
|
|
|
+ sp->psp_data = psp;
|
|
|
+
|
|
|
+ psp->vdata = (struct psp_vdata *)sp->dev_vdata->psp_vdata;
|
|
|
+ if (!psp->vdata) {
|
|
|
+ ret = -ENODEV;
|
|
|
+ dev_err(dev, "missing driver data\n");
|
|
|
+ goto e_err;
|
|
|
+ }
|
|
|
+
|
|
|
+ psp->io_regs = sp->io_map + psp->vdata->offset;
|
|
|
+
|
|
|
+ /* Disable and clear interrupts until ready */
|
|
|
+ iowrite32(0, psp->io_regs + PSP_P2CMSG_INTEN);
|
|
|
+ iowrite32(-1, psp->io_regs + PSP_P2CMSG_INTSTS);
|
|
|
+
|
|
|
+ /* Request an irq */
|
|
|
+ ret = sp_request_psp_irq(psp->sp, psp_irq_handler, psp->name, psp);
|
|
|
+ if (ret) {
|
|
|
+ dev_err(dev, "psp: unable to allocate an IRQ\n");
|
|
|
+ goto e_err;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (sp->set_psp_master_device)
|
|
|
+ sp->set_psp_master_device(sp);
|
|
|
+
|
|
|
+ /* Enable interrupt */
|
|
|
+ iowrite32(-1, psp->io_regs + PSP_P2CMSG_INTEN);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+
|
|
|
+e_err:
|
|
|
+ sp->psp_data = NULL;
|
|
|
+
|
|
|
+ dev_notice(dev, "psp initialization failed\n");
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+void psp_dev_destroy(struct sp_device *sp)
|
|
|
+{
|
|
|
+ struct psp_device *psp = sp->psp_data;
|
|
|
+
|
|
|
+ sp_free_psp_irq(sp, psp);
|
|
|
+}
|