162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * AMD Secure Processor device driver
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2013,2019 Advanced Micro Devices, Inc.
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Author: Tom Lendacky <thomas.lendacky@amd.com>
862306a36Sopenharmony_ci * Author: Gary R Hook <gary.hook@amd.com>
962306a36Sopenharmony_ci */
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <linux/bitfield.h>
1262306a36Sopenharmony_ci#include <linux/module.h>
1362306a36Sopenharmony_ci#include <linux/kernel.h>
1462306a36Sopenharmony_ci#include <linux/device.h>
1562306a36Sopenharmony_ci#include <linux/pci.h>
1662306a36Sopenharmony_ci#include <linux/pci_ids.h>
1762306a36Sopenharmony_ci#include <linux/dma-mapping.h>
1862306a36Sopenharmony_ci#include <linux/kthread.h>
1962306a36Sopenharmony_ci#include <linux/sched.h>
2062306a36Sopenharmony_ci#include <linux/interrupt.h>
2162306a36Sopenharmony_ci#include <linux/spinlock.h>
2262306a36Sopenharmony_ci#include <linux/delay.h>
2362306a36Sopenharmony_ci#include <linux/ccp.h>
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci#include "ccp-dev.h"
2662306a36Sopenharmony_ci#include "psp-dev.h"
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci/* used for version string AA.BB.CC.DD */
2962306a36Sopenharmony_ci#define AA				GENMASK(31, 24)
3062306a36Sopenharmony_ci#define BB				GENMASK(23, 16)
3162306a36Sopenharmony_ci#define CC				GENMASK(15, 8)
3262306a36Sopenharmony_ci#define DD				GENMASK(7, 0)
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci#define MSIX_VECTORS			2
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_cistruct sp_pci {
3762306a36Sopenharmony_ci	int msix_count;
3862306a36Sopenharmony_ci	struct msix_entry msix_entry[MSIX_VECTORS];
3962306a36Sopenharmony_ci};
4062306a36Sopenharmony_cistatic struct sp_device *sp_dev_master;
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci#define security_attribute_show(name, def)					\
4362306a36Sopenharmony_cistatic ssize_t name##_show(struct device *d, struct device_attribute *attr,	\
4462306a36Sopenharmony_ci			   char *buf)						\
4562306a36Sopenharmony_ci{										\
4662306a36Sopenharmony_ci	struct sp_device *sp = dev_get_drvdata(d);				\
4762306a36Sopenharmony_ci	struct psp_device *psp = sp->psp_data;					\
4862306a36Sopenharmony_ci	int bit = PSP_SECURITY_##def << PSP_CAPABILITY_PSP_SECURITY_OFFSET;	\
4962306a36Sopenharmony_ci	return sysfs_emit(buf, "%d\n", (psp->capability & bit) > 0);		\
5062306a36Sopenharmony_ci}
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_cisecurity_attribute_show(fused_part, FUSED_PART)
5362306a36Sopenharmony_cistatic DEVICE_ATTR_RO(fused_part);
5462306a36Sopenharmony_cisecurity_attribute_show(debug_lock_on, DEBUG_LOCK_ON)
5562306a36Sopenharmony_cistatic DEVICE_ATTR_RO(debug_lock_on);
5662306a36Sopenharmony_cisecurity_attribute_show(tsme_status, TSME_STATUS)
5762306a36Sopenharmony_cistatic DEVICE_ATTR_RO(tsme_status);
5862306a36Sopenharmony_cisecurity_attribute_show(anti_rollback_status, ANTI_ROLLBACK_STATUS)
5962306a36Sopenharmony_cistatic DEVICE_ATTR_RO(anti_rollback_status);
6062306a36Sopenharmony_cisecurity_attribute_show(rpmc_production_enabled, RPMC_PRODUCTION_ENABLED)
6162306a36Sopenharmony_cistatic DEVICE_ATTR_RO(rpmc_production_enabled);
6262306a36Sopenharmony_cisecurity_attribute_show(rpmc_spirom_available, RPMC_SPIROM_AVAILABLE)
6362306a36Sopenharmony_cistatic DEVICE_ATTR_RO(rpmc_spirom_available);
6462306a36Sopenharmony_cisecurity_attribute_show(hsp_tpm_available, HSP_TPM_AVAILABLE)
6562306a36Sopenharmony_cistatic DEVICE_ATTR_RO(hsp_tpm_available);
6662306a36Sopenharmony_cisecurity_attribute_show(rom_armor_enforced, ROM_ARMOR_ENFORCED)
6762306a36Sopenharmony_cistatic DEVICE_ATTR_RO(rom_armor_enforced);
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_cistatic struct attribute *psp_security_attrs[] = {
7062306a36Sopenharmony_ci	&dev_attr_fused_part.attr,
7162306a36Sopenharmony_ci	&dev_attr_debug_lock_on.attr,
7262306a36Sopenharmony_ci	&dev_attr_tsme_status.attr,
7362306a36Sopenharmony_ci	&dev_attr_anti_rollback_status.attr,
7462306a36Sopenharmony_ci	&dev_attr_rpmc_production_enabled.attr,
7562306a36Sopenharmony_ci	&dev_attr_rpmc_spirom_available.attr,
7662306a36Sopenharmony_ci	&dev_attr_hsp_tpm_available.attr,
7762306a36Sopenharmony_ci	&dev_attr_rom_armor_enforced.attr,
7862306a36Sopenharmony_ci	NULL
7962306a36Sopenharmony_ci};
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_cistatic umode_t psp_security_is_visible(struct kobject *kobj, struct attribute *attr, int idx)
8262306a36Sopenharmony_ci{
8362306a36Sopenharmony_ci	struct device *dev = kobj_to_dev(kobj);
8462306a36Sopenharmony_ci	struct sp_device *sp = dev_get_drvdata(dev);
8562306a36Sopenharmony_ci	struct psp_device *psp = sp->psp_data;
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	if (psp && (psp->capability & PSP_CAPABILITY_PSP_SECURITY_REPORTING))
8862306a36Sopenharmony_ci		return 0444;
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	return 0;
9162306a36Sopenharmony_ci}
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_cistatic struct attribute_group psp_security_attr_group = {
9462306a36Sopenharmony_ci	.attrs = psp_security_attrs,
9562306a36Sopenharmony_ci	.is_visible = psp_security_is_visible,
9662306a36Sopenharmony_ci};
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci#define version_attribute_show(name, _offset)					\
9962306a36Sopenharmony_cistatic ssize_t name##_show(struct device *d, struct device_attribute *attr,	\
10062306a36Sopenharmony_ci			   char *buf)						\
10162306a36Sopenharmony_ci{										\
10262306a36Sopenharmony_ci	struct sp_device *sp = dev_get_drvdata(d);				\
10362306a36Sopenharmony_ci	struct psp_device *psp = sp->psp_data;					\
10462306a36Sopenharmony_ci	unsigned int val = ioread32(psp->io_regs + _offset);			\
10562306a36Sopenharmony_ci	return sysfs_emit(buf, "%02lx.%02lx.%02lx.%02lx\n",			\
10662306a36Sopenharmony_ci			  FIELD_GET(AA, val),			\
10762306a36Sopenharmony_ci			  FIELD_GET(BB, val),			\
10862306a36Sopenharmony_ci			  FIELD_GET(CC, val),			\
10962306a36Sopenharmony_ci			  FIELD_GET(DD, val));			\
11062306a36Sopenharmony_ci}
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_civersion_attribute_show(bootloader_version, psp->vdata->bootloader_info_reg)
11362306a36Sopenharmony_cistatic DEVICE_ATTR_RO(bootloader_version);
11462306a36Sopenharmony_civersion_attribute_show(tee_version, psp->vdata->tee->info_reg)
11562306a36Sopenharmony_cistatic DEVICE_ATTR_RO(tee_version);
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_cistatic struct attribute *psp_firmware_attrs[] = {
11862306a36Sopenharmony_ci	&dev_attr_bootloader_version.attr,
11962306a36Sopenharmony_ci	&dev_attr_tee_version.attr,
12062306a36Sopenharmony_ci	NULL,
12162306a36Sopenharmony_ci};
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_cistatic umode_t psp_firmware_is_visible(struct kobject *kobj, struct attribute *attr, int idx)
12462306a36Sopenharmony_ci{
12562306a36Sopenharmony_ci	struct device *dev = kobj_to_dev(kobj);
12662306a36Sopenharmony_ci	struct sp_device *sp = dev_get_drvdata(dev);
12762306a36Sopenharmony_ci	struct psp_device *psp = sp->psp_data;
12862306a36Sopenharmony_ci	unsigned int val = 0xffffffff;
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci	if (!psp)
13162306a36Sopenharmony_ci		return 0;
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	if (attr == &dev_attr_bootloader_version.attr &&
13462306a36Sopenharmony_ci	    psp->vdata->bootloader_info_reg)
13562306a36Sopenharmony_ci		val = ioread32(psp->io_regs + psp->vdata->bootloader_info_reg);
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci	if (attr == &dev_attr_tee_version.attr &&
13862306a36Sopenharmony_ci	    psp->capability & PSP_CAPABILITY_TEE &&
13962306a36Sopenharmony_ci	    psp->vdata->tee->info_reg)
14062306a36Sopenharmony_ci		val = ioread32(psp->io_regs + psp->vdata->tee->info_reg);
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	/* If platform disallows accessing this register it will be all f's */
14362306a36Sopenharmony_ci	if (val != 0xffffffff)
14462306a36Sopenharmony_ci		return 0444;
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	return 0;
14762306a36Sopenharmony_ci}
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_cistatic struct attribute_group psp_firmware_attr_group = {
15062306a36Sopenharmony_ci	.attrs = psp_firmware_attrs,
15162306a36Sopenharmony_ci	.is_visible = psp_firmware_is_visible,
15262306a36Sopenharmony_ci};
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_cistatic const struct attribute_group *psp_groups[] = {
15562306a36Sopenharmony_ci	&psp_security_attr_group,
15662306a36Sopenharmony_ci	&psp_firmware_attr_group,
15762306a36Sopenharmony_ci	NULL,
15862306a36Sopenharmony_ci};
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_cistatic int sp_get_msix_irqs(struct sp_device *sp)
16162306a36Sopenharmony_ci{
16262306a36Sopenharmony_ci	struct sp_pci *sp_pci = sp->dev_specific;
16362306a36Sopenharmony_ci	struct device *dev = sp->dev;
16462306a36Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(dev);
16562306a36Sopenharmony_ci	int v, ret;
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	for (v = 0; v < ARRAY_SIZE(sp_pci->msix_entry); v++)
16862306a36Sopenharmony_ci		sp_pci->msix_entry[v].entry = v;
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci	ret = pci_enable_msix_range(pdev, sp_pci->msix_entry, 1, v);
17162306a36Sopenharmony_ci	if (ret < 0)
17262306a36Sopenharmony_ci		return ret;
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci	sp_pci->msix_count = ret;
17562306a36Sopenharmony_ci	sp->use_tasklet = true;
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci	sp->psp_irq = sp_pci->msix_entry[0].vector;
17862306a36Sopenharmony_ci	sp->ccp_irq = (sp_pci->msix_count > 1) ? sp_pci->msix_entry[1].vector
17962306a36Sopenharmony_ci					       : sp_pci->msix_entry[0].vector;
18062306a36Sopenharmony_ci	return 0;
18162306a36Sopenharmony_ci}
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_cistatic int sp_get_msi_irq(struct sp_device *sp)
18462306a36Sopenharmony_ci{
18562306a36Sopenharmony_ci	struct device *dev = sp->dev;
18662306a36Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(dev);
18762306a36Sopenharmony_ci	int ret;
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci	ret = pci_enable_msi(pdev);
19062306a36Sopenharmony_ci	if (ret)
19162306a36Sopenharmony_ci		return ret;
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci	sp->ccp_irq = pdev->irq;
19462306a36Sopenharmony_ci	sp->psp_irq = pdev->irq;
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci	return 0;
19762306a36Sopenharmony_ci}
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_cistatic int sp_get_irqs(struct sp_device *sp)
20062306a36Sopenharmony_ci{
20162306a36Sopenharmony_ci	struct device *dev = sp->dev;
20262306a36Sopenharmony_ci	int ret;
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	ret = sp_get_msix_irqs(sp);
20562306a36Sopenharmony_ci	if (!ret)
20662306a36Sopenharmony_ci		return 0;
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci	/* Couldn't get MSI-X vectors, try MSI */
20962306a36Sopenharmony_ci	dev_notice(dev, "could not enable MSI-X (%d), trying MSI\n", ret);
21062306a36Sopenharmony_ci	ret = sp_get_msi_irq(sp);
21162306a36Sopenharmony_ci	if (!ret)
21262306a36Sopenharmony_ci		return 0;
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci	/* Couldn't get MSI interrupt */
21562306a36Sopenharmony_ci	dev_notice(dev, "could not enable MSI (%d)\n", ret);
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci	return ret;
21862306a36Sopenharmony_ci}
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_cistatic void sp_free_irqs(struct sp_device *sp)
22162306a36Sopenharmony_ci{
22262306a36Sopenharmony_ci	struct sp_pci *sp_pci = sp->dev_specific;
22362306a36Sopenharmony_ci	struct device *dev = sp->dev;
22462306a36Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(dev);
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci	if (sp_pci->msix_count)
22762306a36Sopenharmony_ci		pci_disable_msix(pdev);
22862306a36Sopenharmony_ci	else if (sp->psp_irq)
22962306a36Sopenharmony_ci		pci_disable_msi(pdev);
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	sp->ccp_irq = 0;
23262306a36Sopenharmony_ci	sp->psp_irq = 0;
23362306a36Sopenharmony_ci}
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_cistatic bool sp_pci_is_master(struct sp_device *sp)
23662306a36Sopenharmony_ci{
23762306a36Sopenharmony_ci	struct device *dev_cur, *dev_new;
23862306a36Sopenharmony_ci	struct pci_dev *pdev_cur, *pdev_new;
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci	dev_new = sp->dev;
24162306a36Sopenharmony_ci	dev_cur = sp_dev_master->dev;
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci	pdev_new = to_pci_dev(dev_new);
24462306a36Sopenharmony_ci	pdev_cur = to_pci_dev(dev_cur);
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci	if (pdev_new->bus->number < pdev_cur->bus->number)
24762306a36Sopenharmony_ci		return true;
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	if (PCI_SLOT(pdev_new->devfn) < PCI_SLOT(pdev_cur->devfn))
25062306a36Sopenharmony_ci		return true;
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci	if (PCI_FUNC(pdev_new->devfn) < PCI_FUNC(pdev_cur->devfn))
25362306a36Sopenharmony_ci		return true;
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci	return false;
25662306a36Sopenharmony_ci}
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_cistatic void psp_set_master(struct sp_device *sp)
25962306a36Sopenharmony_ci{
26062306a36Sopenharmony_ci	if (!sp_dev_master) {
26162306a36Sopenharmony_ci		sp_dev_master = sp;
26262306a36Sopenharmony_ci		return;
26362306a36Sopenharmony_ci	}
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	if (sp_pci_is_master(sp))
26662306a36Sopenharmony_ci		sp_dev_master = sp;
26762306a36Sopenharmony_ci}
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_cistatic struct sp_device *psp_get_master(void)
27062306a36Sopenharmony_ci{
27162306a36Sopenharmony_ci	return sp_dev_master;
27262306a36Sopenharmony_ci}
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_cistatic void psp_clear_master(struct sp_device *sp)
27562306a36Sopenharmony_ci{
27662306a36Sopenharmony_ci	if (sp == sp_dev_master) {
27762306a36Sopenharmony_ci		sp_dev_master = NULL;
27862306a36Sopenharmony_ci		dev_dbg(sp->dev, "Cleared sp_dev_master\n");
27962306a36Sopenharmony_ci	}
28062306a36Sopenharmony_ci}
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_cistatic int sp_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
28362306a36Sopenharmony_ci{
28462306a36Sopenharmony_ci	struct sp_device *sp;
28562306a36Sopenharmony_ci	struct sp_pci *sp_pci;
28662306a36Sopenharmony_ci	struct device *dev = &pdev->dev;
28762306a36Sopenharmony_ci	void __iomem * const *iomap_table;
28862306a36Sopenharmony_ci	int bar_mask;
28962306a36Sopenharmony_ci	int ret;
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci	ret = -ENOMEM;
29262306a36Sopenharmony_ci	sp = sp_alloc_struct(dev);
29362306a36Sopenharmony_ci	if (!sp)
29462306a36Sopenharmony_ci		goto e_err;
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci	sp_pci = devm_kzalloc(dev, sizeof(*sp_pci), GFP_KERNEL);
29762306a36Sopenharmony_ci	if (!sp_pci)
29862306a36Sopenharmony_ci		goto e_err;
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci	sp->dev_specific = sp_pci;
30162306a36Sopenharmony_ci	sp->dev_vdata = (struct sp_dev_vdata *)id->driver_data;
30262306a36Sopenharmony_ci	if (!sp->dev_vdata) {
30362306a36Sopenharmony_ci		ret = -ENODEV;
30462306a36Sopenharmony_ci		dev_err(dev, "missing driver data\n");
30562306a36Sopenharmony_ci		goto e_err;
30662306a36Sopenharmony_ci	}
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci	ret = pcim_enable_device(pdev);
30962306a36Sopenharmony_ci	if (ret) {
31062306a36Sopenharmony_ci		dev_err(dev, "pcim_enable_device failed (%d)\n", ret);
31162306a36Sopenharmony_ci		goto e_err;
31262306a36Sopenharmony_ci	}
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	bar_mask = pci_select_bars(pdev, IORESOURCE_MEM);
31562306a36Sopenharmony_ci	ret = pcim_iomap_regions(pdev, bar_mask, "ccp");
31662306a36Sopenharmony_ci	if (ret) {
31762306a36Sopenharmony_ci		dev_err(dev, "pcim_iomap_regions failed (%d)\n", ret);
31862306a36Sopenharmony_ci		goto e_err;
31962306a36Sopenharmony_ci	}
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci	iomap_table = pcim_iomap_table(pdev);
32262306a36Sopenharmony_ci	if (!iomap_table) {
32362306a36Sopenharmony_ci		dev_err(dev, "pcim_iomap_table failed\n");
32462306a36Sopenharmony_ci		ret = -ENOMEM;
32562306a36Sopenharmony_ci		goto e_err;
32662306a36Sopenharmony_ci	}
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	sp->io_map = iomap_table[sp->dev_vdata->bar];
32962306a36Sopenharmony_ci	if (!sp->io_map) {
33062306a36Sopenharmony_ci		dev_err(dev, "ioremap failed\n");
33162306a36Sopenharmony_ci		ret = -ENOMEM;
33262306a36Sopenharmony_ci		goto e_err;
33362306a36Sopenharmony_ci	}
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci	ret = sp_get_irqs(sp);
33662306a36Sopenharmony_ci	if (ret)
33762306a36Sopenharmony_ci		goto e_err;
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci	pci_set_master(pdev);
34062306a36Sopenharmony_ci	sp->set_psp_master_device = psp_set_master;
34162306a36Sopenharmony_ci	sp->get_psp_master_device = psp_get_master;
34262306a36Sopenharmony_ci	sp->clear_psp_master_device = psp_clear_master;
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci	ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(48));
34562306a36Sopenharmony_ci	if (ret) {
34662306a36Sopenharmony_ci		ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
34762306a36Sopenharmony_ci		if (ret) {
34862306a36Sopenharmony_ci			dev_err(dev, "dma_set_mask_and_coherent failed (%d)\n",
34962306a36Sopenharmony_ci				ret);
35062306a36Sopenharmony_ci			goto free_irqs;
35162306a36Sopenharmony_ci		}
35262306a36Sopenharmony_ci	}
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci	dev_set_drvdata(dev, sp);
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	ret = sp_init(sp);
35762306a36Sopenharmony_ci	if (ret)
35862306a36Sopenharmony_ci		goto free_irqs;
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci	return 0;
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_cifree_irqs:
36362306a36Sopenharmony_ci	sp_free_irqs(sp);
36462306a36Sopenharmony_cie_err:
36562306a36Sopenharmony_ci	dev_notice(dev, "initialization failed\n");
36662306a36Sopenharmony_ci	return ret;
36762306a36Sopenharmony_ci}
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_cistatic void sp_pci_shutdown(struct pci_dev *pdev)
37062306a36Sopenharmony_ci{
37162306a36Sopenharmony_ci	struct device *dev = &pdev->dev;
37262306a36Sopenharmony_ci	struct sp_device *sp = dev_get_drvdata(dev);
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci	if (!sp)
37562306a36Sopenharmony_ci		return;
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci	sp_destroy(sp);
37862306a36Sopenharmony_ci}
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_cistatic void sp_pci_remove(struct pci_dev *pdev)
38162306a36Sopenharmony_ci{
38262306a36Sopenharmony_ci	struct device *dev = &pdev->dev;
38362306a36Sopenharmony_ci	struct sp_device *sp = dev_get_drvdata(dev);
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci	if (!sp)
38662306a36Sopenharmony_ci		return;
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci	sp_destroy(sp);
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci	sp_free_irqs(sp);
39162306a36Sopenharmony_ci}
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_cistatic int __maybe_unused sp_pci_suspend(struct device *dev)
39462306a36Sopenharmony_ci{
39562306a36Sopenharmony_ci	struct sp_device *sp = dev_get_drvdata(dev);
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci	return sp_suspend(sp);
39862306a36Sopenharmony_ci}
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_cistatic int __maybe_unused sp_pci_resume(struct device *dev)
40162306a36Sopenharmony_ci{
40262306a36Sopenharmony_ci	struct sp_device *sp = dev_get_drvdata(dev);
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_ci	return sp_resume(sp);
40562306a36Sopenharmony_ci}
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci#ifdef CONFIG_CRYPTO_DEV_SP_PSP
40862306a36Sopenharmony_cistatic const struct sev_vdata sevv1 = {
40962306a36Sopenharmony_ci	.cmdresp_reg		= 0x10580,	/* C2PMSG_32 */
41062306a36Sopenharmony_ci	.cmdbuff_addr_lo_reg	= 0x105e0,	/* C2PMSG_56 */
41162306a36Sopenharmony_ci	.cmdbuff_addr_hi_reg	= 0x105e4,	/* C2PMSG_57 */
41262306a36Sopenharmony_ci};
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_cistatic const struct sev_vdata sevv2 = {
41562306a36Sopenharmony_ci	.cmdresp_reg		= 0x10980,	/* C2PMSG_32 */
41662306a36Sopenharmony_ci	.cmdbuff_addr_lo_reg	= 0x109e0,	/* C2PMSG_56 */
41762306a36Sopenharmony_ci	.cmdbuff_addr_hi_reg	= 0x109e4,	/* C2PMSG_57 */
41862306a36Sopenharmony_ci};
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_cistatic const struct tee_vdata teev1 = {
42162306a36Sopenharmony_ci	.cmdresp_reg		= 0x10544,	/* C2PMSG_17 */
42262306a36Sopenharmony_ci	.cmdbuff_addr_lo_reg	= 0x10548,	/* C2PMSG_18 */
42362306a36Sopenharmony_ci	.cmdbuff_addr_hi_reg	= 0x1054c,	/* C2PMSG_19 */
42462306a36Sopenharmony_ci	.ring_wptr_reg          = 0x10550,	/* C2PMSG_20 */
42562306a36Sopenharmony_ci	.ring_rptr_reg          = 0x10554,	/* C2PMSG_21 */
42662306a36Sopenharmony_ci	.info_reg		= 0x109e8,	/* C2PMSG_58 */
42762306a36Sopenharmony_ci};
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_cistatic const struct tee_vdata teev2 = {
43062306a36Sopenharmony_ci	.cmdresp_reg		= 0x10944,	/* C2PMSG_17 */
43162306a36Sopenharmony_ci	.cmdbuff_addr_lo_reg	= 0x10948,	/* C2PMSG_18 */
43262306a36Sopenharmony_ci	.cmdbuff_addr_hi_reg	= 0x1094c,	/* C2PMSG_19 */
43362306a36Sopenharmony_ci	.ring_wptr_reg		= 0x10950,	/* C2PMSG_20 */
43462306a36Sopenharmony_ci	.ring_rptr_reg		= 0x10954,	/* C2PMSG_21 */
43562306a36Sopenharmony_ci};
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_cistatic const struct platform_access_vdata pa_v1 = {
43862306a36Sopenharmony_ci	.cmdresp_reg		= 0x10570,	/* C2PMSG_28 */
43962306a36Sopenharmony_ci	.cmdbuff_addr_lo_reg	= 0x10574,	/* C2PMSG_29 */
44062306a36Sopenharmony_ci	.cmdbuff_addr_hi_reg	= 0x10578,	/* C2PMSG_30 */
44162306a36Sopenharmony_ci	.doorbell_button_reg	= 0x10a24,	/* C2PMSG_73 */
44262306a36Sopenharmony_ci	.doorbell_cmd_reg	= 0x10a40,	/* C2PMSG_80 */
44362306a36Sopenharmony_ci};
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_cistatic const struct platform_access_vdata pa_v2 = {
44662306a36Sopenharmony_ci	.doorbell_button_reg	= 0x10a24,	/* C2PMSG_73 */
44762306a36Sopenharmony_ci	.doorbell_cmd_reg	= 0x10a40,	/* C2PMSG_80 */
44862306a36Sopenharmony_ci};
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_cistatic const struct psp_vdata pspv1 = {
45162306a36Sopenharmony_ci	.sev			= &sevv1,
45262306a36Sopenharmony_ci	.bootloader_info_reg	= 0x105ec,	/* C2PMSG_59 */
45362306a36Sopenharmony_ci	.feature_reg		= 0x105fc,	/* C2PMSG_63 */
45462306a36Sopenharmony_ci	.inten_reg		= 0x10610,	/* P2CMSG_INTEN */
45562306a36Sopenharmony_ci	.intsts_reg		= 0x10614,	/* P2CMSG_INTSTS */
45662306a36Sopenharmony_ci};
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_cistatic const struct psp_vdata pspv2 = {
45962306a36Sopenharmony_ci	.sev			= &sevv2,
46062306a36Sopenharmony_ci	.bootloader_info_reg	= 0x109ec,	/* C2PMSG_59 */
46162306a36Sopenharmony_ci	.feature_reg		= 0x109fc,	/* C2PMSG_63 */
46262306a36Sopenharmony_ci	.inten_reg		= 0x10690,	/* P2CMSG_INTEN */
46362306a36Sopenharmony_ci	.intsts_reg		= 0x10694,	/* P2CMSG_INTSTS */
46462306a36Sopenharmony_ci};
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_cistatic const struct psp_vdata pspv3 = {
46762306a36Sopenharmony_ci	.tee			= &teev1,
46862306a36Sopenharmony_ci	.platform_access	= &pa_v1,
46962306a36Sopenharmony_ci	.bootloader_info_reg	= 0x109ec,	/* C2PMSG_59 */
47062306a36Sopenharmony_ci	.feature_reg		= 0x109fc,	/* C2PMSG_63 */
47162306a36Sopenharmony_ci	.inten_reg		= 0x10690,	/* P2CMSG_INTEN */
47262306a36Sopenharmony_ci	.intsts_reg		= 0x10694,	/* P2CMSG_INTSTS */
47362306a36Sopenharmony_ci	.platform_features	= PLATFORM_FEATURE_DBC,
47462306a36Sopenharmony_ci};
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_cistatic const struct psp_vdata pspv4 = {
47762306a36Sopenharmony_ci	.sev			= &sevv2,
47862306a36Sopenharmony_ci	.tee			= &teev1,
47962306a36Sopenharmony_ci	.bootloader_info_reg	= 0x109ec,	/* C2PMSG_59 */
48062306a36Sopenharmony_ci	.feature_reg		= 0x109fc,	/* C2PMSG_63 */
48162306a36Sopenharmony_ci	.inten_reg		= 0x10690,	/* P2CMSG_INTEN */
48262306a36Sopenharmony_ci	.intsts_reg		= 0x10694,	/* P2CMSG_INTSTS */
48362306a36Sopenharmony_ci};
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_cistatic const struct psp_vdata pspv5 = {
48662306a36Sopenharmony_ci	.tee			= &teev2,
48762306a36Sopenharmony_ci	.platform_access	= &pa_v2,
48862306a36Sopenharmony_ci	.feature_reg		= 0x109fc,	/* C2PMSG_63 */
48962306a36Sopenharmony_ci	.inten_reg		= 0x10510,	/* P2CMSG_INTEN */
49062306a36Sopenharmony_ci	.intsts_reg		= 0x10514,	/* P2CMSG_INTSTS */
49162306a36Sopenharmony_ci};
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_cistatic const struct psp_vdata pspv6 = {
49462306a36Sopenharmony_ci	.sev                    = &sevv2,
49562306a36Sopenharmony_ci	.tee                    = &teev2,
49662306a36Sopenharmony_ci	.feature_reg            = 0x109fc,	/* C2PMSG_63 */
49762306a36Sopenharmony_ci	.inten_reg              = 0x10510,	/* P2CMSG_INTEN */
49862306a36Sopenharmony_ci	.intsts_reg             = 0x10514,	/* P2CMSG_INTSTS */
49962306a36Sopenharmony_ci};
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_ci#endif
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_cistatic const struct sp_dev_vdata dev_vdata[] = {
50462306a36Sopenharmony_ci	{	/* 0 */
50562306a36Sopenharmony_ci		.bar = 2,
50662306a36Sopenharmony_ci#ifdef CONFIG_CRYPTO_DEV_SP_CCP
50762306a36Sopenharmony_ci		.ccp_vdata = &ccpv3,
50862306a36Sopenharmony_ci#endif
50962306a36Sopenharmony_ci	},
51062306a36Sopenharmony_ci	{	/* 1 */
51162306a36Sopenharmony_ci		.bar = 2,
51262306a36Sopenharmony_ci#ifdef CONFIG_CRYPTO_DEV_SP_CCP
51362306a36Sopenharmony_ci		.ccp_vdata = &ccpv5a,
51462306a36Sopenharmony_ci#endif
51562306a36Sopenharmony_ci#ifdef CONFIG_CRYPTO_DEV_SP_PSP
51662306a36Sopenharmony_ci		.psp_vdata = &pspv1,
51762306a36Sopenharmony_ci#endif
51862306a36Sopenharmony_ci	},
51962306a36Sopenharmony_ci	{	/* 2 */
52062306a36Sopenharmony_ci		.bar = 2,
52162306a36Sopenharmony_ci#ifdef CONFIG_CRYPTO_DEV_SP_CCP
52262306a36Sopenharmony_ci		.ccp_vdata = &ccpv5b,
52362306a36Sopenharmony_ci#endif
52462306a36Sopenharmony_ci	},
52562306a36Sopenharmony_ci	{	/* 3 */
52662306a36Sopenharmony_ci		.bar = 2,
52762306a36Sopenharmony_ci#ifdef CONFIG_CRYPTO_DEV_SP_CCP
52862306a36Sopenharmony_ci		.ccp_vdata = &ccpv5a,
52962306a36Sopenharmony_ci#endif
53062306a36Sopenharmony_ci#ifdef CONFIG_CRYPTO_DEV_SP_PSP
53162306a36Sopenharmony_ci		.psp_vdata = &pspv2,
53262306a36Sopenharmony_ci#endif
53362306a36Sopenharmony_ci	},
53462306a36Sopenharmony_ci	{	/* 4 */
53562306a36Sopenharmony_ci		.bar = 2,
53662306a36Sopenharmony_ci#ifdef CONFIG_CRYPTO_DEV_SP_CCP
53762306a36Sopenharmony_ci		.ccp_vdata = &ccpv5a,
53862306a36Sopenharmony_ci#endif
53962306a36Sopenharmony_ci#ifdef CONFIG_CRYPTO_DEV_SP_PSP
54062306a36Sopenharmony_ci		.psp_vdata = &pspv3,
54162306a36Sopenharmony_ci#endif
54262306a36Sopenharmony_ci	},
54362306a36Sopenharmony_ci	{	/* 5 */
54462306a36Sopenharmony_ci		.bar = 2,
54562306a36Sopenharmony_ci#ifdef CONFIG_CRYPTO_DEV_SP_PSP
54662306a36Sopenharmony_ci		.psp_vdata = &pspv4,
54762306a36Sopenharmony_ci#endif
54862306a36Sopenharmony_ci	},
54962306a36Sopenharmony_ci	{	/* 6 */
55062306a36Sopenharmony_ci		.bar = 2,
55162306a36Sopenharmony_ci#ifdef CONFIG_CRYPTO_DEV_SP_PSP
55262306a36Sopenharmony_ci		.psp_vdata = &pspv3,
55362306a36Sopenharmony_ci#endif
55462306a36Sopenharmony_ci	},
55562306a36Sopenharmony_ci	{	/* 7 */
55662306a36Sopenharmony_ci		.bar = 2,
55762306a36Sopenharmony_ci#ifdef CONFIG_CRYPTO_DEV_SP_PSP
55862306a36Sopenharmony_ci		.psp_vdata = &pspv5,
55962306a36Sopenharmony_ci#endif
56062306a36Sopenharmony_ci	},
56162306a36Sopenharmony_ci	{	/* 8 */
56262306a36Sopenharmony_ci		.bar = 2,
56362306a36Sopenharmony_ci#ifdef CONFIG_CRYPTO_DEV_SP_PSP
56462306a36Sopenharmony_ci		.psp_vdata = &pspv6,
56562306a36Sopenharmony_ci#endif
56662306a36Sopenharmony_ci	},
56762306a36Sopenharmony_ci};
56862306a36Sopenharmony_cistatic const struct pci_device_id sp_pci_table[] = {
56962306a36Sopenharmony_ci	{ PCI_VDEVICE(AMD, 0x1537), (kernel_ulong_t)&dev_vdata[0] },
57062306a36Sopenharmony_ci	{ PCI_VDEVICE(AMD, 0x1456), (kernel_ulong_t)&dev_vdata[1] },
57162306a36Sopenharmony_ci	{ PCI_VDEVICE(AMD, 0x1468), (kernel_ulong_t)&dev_vdata[2] },
57262306a36Sopenharmony_ci	{ PCI_VDEVICE(AMD, 0x1486), (kernel_ulong_t)&dev_vdata[3] },
57362306a36Sopenharmony_ci	{ PCI_VDEVICE(AMD, 0x15DF), (kernel_ulong_t)&dev_vdata[4] },
57462306a36Sopenharmony_ci	{ PCI_VDEVICE(AMD, 0x14CA), (kernel_ulong_t)&dev_vdata[5] },
57562306a36Sopenharmony_ci	{ PCI_VDEVICE(AMD, 0x15C7), (kernel_ulong_t)&dev_vdata[6] },
57662306a36Sopenharmony_ci	{ PCI_VDEVICE(AMD, 0x1649), (kernel_ulong_t)&dev_vdata[6] },
57762306a36Sopenharmony_ci	{ PCI_VDEVICE(AMD, 0x17E0), (kernel_ulong_t)&dev_vdata[7] },
57862306a36Sopenharmony_ci	{ PCI_VDEVICE(AMD, 0x156E), (kernel_ulong_t)&dev_vdata[8] },
57962306a36Sopenharmony_ci	/* Last entry must be zero */
58062306a36Sopenharmony_ci	{ 0, }
58162306a36Sopenharmony_ci};
58262306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, sp_pci_table);
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(sp_pci_pm_ops, sp_pci_suspend, sp_pci_resume);
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_cistatic struct pci_driver sp_pci_driver = {
58762306a36Sopenharmony_ci	.name = "ccp",
58862306a36Sopenharmony_ci	.id_table = sp_pci_table,
58962306a36Sopenharmony_ci	.probe = sp_pci_probe,
59062306a36Sopenharmony_ci	.remove = sp_pci_remove,
59162306a36Sopenharmony_ci	.shutdown = sp_pci_shutdown,
59262306a36Sopenharmony_ci	.driver.pm = &sp_pci_pm_ops,
59362306a36Sopenharmony_ci	.dev_groups = psp_groups,
59462306a36Sopenharmony_ci};
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_ciint sp_pci_init(void)
59762306a36Sopenharmony_ci{
59862306a36Sopenharmony_ci	return pci_register_driver(&sp_pci_driver);
59962306a36Sopenharmony_ci}
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_civoid sp_pci_exit(void)
60262306a36Sopenharmony_ci{
60362306a36Sopenharmony_ci	pci_unregister_driver(&sp_pci_driver);
60462306a36Sopenharmony_ci}
605