Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * AMD Secure Processor device driver
0004  *
0005  * Copyright (C) 2014,2018 Advanced Micro Devices, Inc.
0006  *
0007  * Author: Tom Lendacky <thomas.lendacky@amd.com>
0008  */
0009 
0010 #include <linux/module.h>
0011 #include <linux/kernel.h>
0012 #include <linux/device.h>
0013 #include <linux/platform_device.h>
0014 #include <linux/ioport.h>
0015 #include <linux/dma-mapping.h>
0016 #include <linux/kthread.h>
0017 #include <linux/sched.h>
0018 #include <linux/interrupt.h>
0019 #include <linux/spinlock.h>
0020 #include <linux/delay.h>
0021 #include <linux/ccp.h>
0022 #include <linux/of.h>
0023 #include <linux/of_address.h>
0024 #include <linux/acpi.h>
0025 
0026 #include "ccp-dev.h"
0027 
0028 struct sp_platform {
0029     int coherent;
0030     unsigned int irq_count;
0031 };
0032 
0033 static const struct sp_dev_vdata dev_vdata[] = {
0034     {
0035         .bar = 0,
0036 #ifdef CONFIG_CRYPTO_DEV_SP_CCP
0037         .ccp_vdata = &ccpv3_platform,
0038 #endif
0039     },
0040 };
0041 
0042 #ifdef CONFIG_ACPI
0043 static const struct acpi_device_id sp_acpi_match[] = {
0044     { "AMDI0C00", (kernel_ulong_t)&dev_vdata[0] },
0045     { },
0046 };
0047 MODULE_DEVICE_TABLE(acpi, sp_acpi_match);
0048 #endif
0049 
0050 #ifdef CONFIG_OF
0051 static const struct of_device_id sp_of_match[] = {
0052     { .compatible = "amd,ccp-seattle-v1a",
0053       .data = (const void *)&dev_vdata[0] },
0054     { },
0055 };
0056 MODULE_DEVICE_TABLE(of, sp_of_match);
0057 #endif
0058 
0059 static struct sp_dev_vdata *sp_get_of_version(struct platform_device *pdev)
0060 {
0061 #ifdef CONFIG_OF
0062     const struct of_device_id *match;
0063 
0064     match = of_match_node(sp_of_match, pdev->dev.of_node);
0065     if (match && match->data)
0066         return (struct sp_dev_vdata *)match->data;
0067 #endif
0068     return NULL;
0069 }
0070 
0071 static struct sp_dev_vdata *sp_get_acpi_version(struct platform_device *pdev)
0072 {
0073 #ifdef CONFIG_ACPI
0074     const struct acpi_device_id *match;
0075 
0076     match = acpi_match_device(sp_acpi_match, &pdev->dev);
0077     if (match && match->driver_data)
0078         return (struct sp_dev_vdata *)match->driver_data;
0079 #endif
0080     return NULL;
0081 }
0082 
0083 static int sp_get_irqs(struct sp_device *sp)
0084 {
0085     struct sp_platform *sp_platform = sp->dev_specific;
0086     struct device *dev = sp->dev;
0087     struct platform_device *pdev = to_platform_device(dev);
0088     int ret;
0089 
0090     sp_platform->irq_count = platform_irq_count(pdev);
0091 
0092     ret = platform_get_irq(pdev, 0);
0093     if (ret < 0) {
0094         dev_notice(dev, "unable to get IRQ (%d)\n", ret);
0095         return ret;
0096     }
0097 
0098     sp->psp_irq = ret;
0099     if (sp_platform->irq_count == 1) {
0100         sp->ccp_irq = ret;
0101     } else {
0102         ret = platform_get_irq(pdev, 1);
0103         if (ret < 0) {
0104             dev_notice(dev, "unable to get IRQ (%d)\n", ret);
0105             return ret;
0106         }
0107 
0108         sp->ccp_irq = ret;
0109     }
0110 
0111     return 0;
0112 }
0113 
0114 static int sp_platform_probe(struct platform_device *pdev)
0115 {
0116     struct sp_device *sp;
0117     struct sp_platform *sp_platform;
0118     struct device *dev = &pdev->dev;
0119     enum dev_dma_attr attr;
0120     int ret;
0121 
0122     ret = -ENOMEM;
0123     sp = sp_alloc_struct(dev);
0124     if (!sp)
0125         goto e_err;
0126 
0127     sp_platform = devm_kzalloc(dev, sizeof(*sp_platform), GFP_KERNEL);
0128     if (!sp_platform)
0129         goto e_err;
0130 
0131     sp->dev_specific = sp_platform;
0132     sp->dev_vdata = pdev->dev.of_node ? sp_get_of_version(pdev)
0133                      : sp_get_acpi_version(pdev);
0134     if (!sp->dev_vdata) {
0135         ret = -ENODEV;
0136         dev_err(dev, "missing driver data\n");
0137         goto e_err;
0138     }
0139 
0140     sp->io_map = devm_platform_ioremap_resource(pdev, 0);
0141     if (IS_ERR(sp->io_map)) {
0142         ret = PTR_ERR(sp->io_map);
0143         goto e_err;
0144     }
0145 
0146     attr = device_get_dma_attr(dev);
0147     if (attr == DEV_DMA_NOT_SUPPORTED) {
0148         dev_err(dev, "DMA is not supported");
0149         goto e_err;
0150     }
0151 
0152     sp_platform->coherent = (attr == DEV_DMA_COHERENT);
0153     if (sp_platform->coherent)
0154         sp->axcache = CACHE_WB_NO_ALLOC;
0155     else
0156         sp->axcache = CACHE_NONE;
0157 
0158     ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(48));
0159     if (ret) {
0160         dev_err(dev, "dma_set_mask_and_coherent failed (%d)\n", ret);
0161         goto e_err;
0162     }
0163 
0164     ret = sp_get_irqs(sp);
0165     if (ret)
0166         goto e_err;
0167 
0168     dev_set_drvdata(dev, sp);
0169 
0170     ret = sp_init(sp);
0171     if (ret)
0172         goto e_err;
0173 
0174     dev_notice(dev, "enabled\n");
0175 
0176     return 0;
0177 
0178 e_err:
0179     dev_notice(dev, "initialization failed\n");
0180     return ret;
0181 }
0182 
0183 static int sp_platform_remove(struct platform_device *pdev)
0184 {
0185     struct device *dev = &pdev->dev;
0186     struct sp_device *sp = dev_get_drvdata(dev);
0187 
0188     sp_destroy(sp);
0189 
0190     dev_notice(dev, "disabled\n");
0191 
0192     return 0;
0193 }
0194 
0195 #ifdef CONFIG_PM
0196 static int sp_platform_suspend(struct platform_device *pdev,
0197                 pm_message_t state)
0198 {
0199     struct device *dev = &pdev->dev;
0200     struct sp_device *sp = dev_get_drvdata(dev);
0201 
0202     return sp_suspend(sp);
0203 }
0204 
0205 static int sp_platform_resume(struct platform_device *pdev)
0206 {
0207     struct device *dev = &pdev->dev;
0208     struct sp_device *sp = dev_get_drvdata(dev);
0209 
0210     return sp_resume(sp);
0211 }
0212 #endif
0213 
0214 static struct platform_driver sp_platform_driver = {
0215     .driver = {
0216         .name = "ccp",
0217 #ifdef CONFIG_ACPI
0218         .acpi_match_table = sp_acpi_match,
0219 #endif
0220 #ifdef CONFIG_OF
0221         .of_match_table = sp_of_match,
0222 #endif
0223     },
0224     .probe = sp_platform_probe,
0225     .remove = sp_platform_remove,
0226 #ifdef CONFIG_PM
0227     .suspend = sp_platform_suspend,
0228     .resume = sp_platform_resume,
0229 #endif
0230 };
0231 
0232 int sp_platform_init(void)
0233 {
0234     return platform_driver_register(&sp_platform_driver);
0235 }
0236 
0237 void sp_platform_exit(void)
0238 {
0239     platform_driver_unregister(&sp_platform_driver);
0240 }