229 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * AMD Secure Processor device driver4 *5 * Copyright (C) 2014,2018 Advanced Micro Devices, Inc.6 *7 * Author: Tom Lendacky <thomas.lendacky@amd.com>8 */9 10#include <linux/module.h>11#include <linux/kernel.h>12#include <linux/device.h>13#include <linux/platform_device.h>14#include <linux/ioport.h>15#include <linux/dma-mapping.h>16#include <linux/kthread.h>17#include <linux/sched.h>18#include <linux/interrupt.h>19#include <linux/spinlock.h>20#include <linux/delay.h>21#include <linux/ccp.h>22#include <linux/of.h>23#include <linux/of_address.h>24#include <linux/acpi.h>25 26#include "ccp-dev.h"27 28struct sp_platform {29 int coherent;30 unsigned int irq_count;31};32 33static const struct sp_dev_vdata dev_vdata[] = {34 {35 .bar = 0,36#ifdef CONFIG_CRYPTO_DEV_SP_CCP37 .ccp_vdata = &ccpv3_platform,38#endif39 },40};41 42static const struct acpi_device_id sp_acpi_match[] = {43 { "AMDI0C00", (kernel_ulong_t)&dev_vdata[0] },44 { },45};46MODULE_DEVICE_TABLE(acpi, sp_acpi_match);47 48static const struct of_device_id sp_of_match[] = {49 { .compatible = "amd,ccp-seattle-v1a",50 .data = (const void *)&dev_vdata[0] },51 { },52};53MODULE_DEVICE_TABLE(of, sp_of_match);54 55static struct sp_dev_vdata *sp_get_of_version(struct platform_device *pdev)56{57 const struct of_device_id *match;58 59 match = of_match_node(sp_of_match, pdev->dev.of_node);60 if (match && match->data)61 return (struct sp_dev_vdata *)match->data;62 63 return NULL;64}65 66static struct sp_dev_vdata *sp_get_acpi_version(struct platform_device *pdev)67{68 const struct acpi_device_id *match;69 70 match = acpi_match_device(sp_acpi_match, &pdev->dev);71 if (match && match->driver_data)72 return (struct sp_dev_vdata *)match->driver_data;73 74 return NULL;75}76 77static int sp_get_irqs(struct sp_device *sp)78{79 struct sp_platform *sp_platform = sp->dev_specific;80 struct device *dev = sp->dev;81 struct platform_device *pdev = to_platform_device(dev);82 int ret;83 84 sp_platform->irq_count = platform_irq_count(pdev);85 86 ret = platform_get_irq(pdev, 0);87 if (ret < 0) {88 dev_notice(dev, "unable to get IRQ (%d)\n", ret);89 return ret;90 }91 92 sp->psp_irq = ret;93 if (sp_platform->irq_count == 1) {94 sp->ccp_irq = ret;95 } else {96 ret = platform_get_irq(pdev, 1);97 if (ret < 0) {98 dev_notice(dev, "unable to get IRQ (%d)\n", ret);99 return ret;100 }101 102 sp->ccp_irq = ret;103 }104 105 return 0;106}107 108static int sp_platform_probe(struct platform_device *pdev)109{110 struct sp_device *sp;111 struct sp_platform *sp_platform;112 struct device *dev = &pdev->dev;113 enum dev_dma_attr attr;114 int ret;115 116 ret = -ENOMEM;117 sp = sp_alloc_struct(dev);118 if (!sp)119 goto e_err;120 121 sp_platform = devm_kzalloc(dev, sizeof(*sp_platform), GFP_KERNEL);122 if (!sp_platform)123 goto e_err;124 125 sp->dev_specific = sp_platform;126 sp->dev_vdata = pdev->dev.of_node ? sp_get_of_version(pdev)127 : sp_get_acpi_version(pdev);128 if (!sp->dev_vdata) {129 ret = -ENODEV;130 dev_err(dev, "missing driver data\n");131 goto e_err;132 }133 134 sp->io_map = devm_platform_ioremap_resource(pdev, 0);135 if (IS_ERR(sp->io_map)) {136 ret = PTR_ERR(sp->io_map);137 goto e_err;138 }139 140 attr = device_get_dma_attr(dev);141 if (attr == DEV_DMA_NOT_SUPPORTED) {142 dev_err(dev, "DMA is not supported");143 goto e_err;144 }145 146 sp_platform->coherent = (attr == DEV_DMA_COHERENT);147 if (sp_platform->coherent)148 sp->axcache = CACHE_WB_NO_ALLOC;149 else150 sp->axcache = CACHE_NONE;151 152 ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(48));153 if (ret) {154 dev_err(dev, "dma_set_mask_and_coherent failed (%d)\n", ret);155 goto e_err;156 }157 158 ret = sp_get_irqs(sp);159 if (ret)160 goto e_err;161 162 dev_set_drvdata(dev, sp);163 164 ret = sp_init(sp);165 if (ret)166 goto e_err;167 168 dev_notice(dev, "enabled\n");169 170 return 0;171 172e_err:173 dev_notice(dev, "initialization failed\n");174 return ret;175}176 177static void sp_platform_remove(struct platform_device *pdev)178{179 struct device *dev = &pdev->dev;180 struct sp_device *sp = dev_get_drvdata(dev);181 182 sp_destroy(sp);183 184 dev_notice(dev, "disabled\n");185}186 187#ifdef CONFIG_PM188static int sp_platform_suspend(struct platform_device *pdev,189 pm_message_t state)190{191 struct device *dev = &pdev->dev;192 struct sp_device *sp = dev_get_drvdata(dev);193 194 return sp_suspend(sp);195}196 197static int sp_platform_resume(struct platform_device *pdev)198{199 struct device *dev = &pdev->dev;200 struct sp_device *sp = dev_get_drvdata(dev);201 202 return sp_resume(sp);203}204#endif205 206static struct platform_driver sp_platform_driver = {207 .driver = {208 .name = "ccp",209 .acpi_match_table = sp_acpi_match,210 .of_match_table = sp_of_match,211 },212 .probe = sp_platform_probe,213 .remove_new = sp_platform_remove,214#ifdef CONFIG_PM215 .suspend = sp_platform_suspend,216 .resume = sp_platform_resume,217#endif218};219 220int sp_platform_init(void)221{222 return platform_driver_register(&sp_platform_driver);223}224 225void sp_platform_exit(void)226{227 platform_driver_unregister(&sp_platform_driver);228}229