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