sp-platform.c (4933B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * AMD Secure Processor device driver 4 * 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_CCP 37 .ccp_vdata = &ccpv3_platform, 38#endif 39 }, 40}; 41 42#ifdef CONFIG_ACPI 43static const struct acpi_device_id sp_acpi_match[] = { 44 { "AMDI0C00", (kernel_ulong_t)&dev_vdata[0] }, 45 { }, 46}; 47MODULE_DEVICE_TABLE(acpi, sp_acpi_match); 48#endif 49 50#ifdef CONFIG_OF 51static const struct of_device_id sp_of_match[] = { 52 { .compatible = "amd,ccp-seattle-v1a", 53 .data = (const void *)&dev_vdata[0] }, 54 { }, 55}; 56MODULE_DEVICE_TABLE(of, sp_of_match); 57#endif 58 59static struct sp_dev_vdata *sp_get_of_version(struct platform_device *pdev) 60{ 61#ifdef CONFIG_OF 62 const struct of_device_id *match; 63 64 match = of_match_node(sp_of_match, pdev->dev.of_node); 65 if (match && match->data) 66 return (struct sp_dev_vdata *)match->data; 67#endif 68 return NULL; 69} 70 71static struct sp_dev_vdata *sp_get_acpi_version(struct platform_device *pdev) 72{ 73#ifdef CONFIG_ACPI 74 const struct acpi_device_id *match; 75 76 match = acpi_match_device(sp_acpi_match, &pdev->dev); 77 if (match && match->driver_data) 78 return (struct sp_dev_vdata *)match->driver_data; 79#endif 80 return NULL; 81} 82 83static int sp_get_irqs(struct sp_device *sp) 84{ 85 struct sp_platform *sp_platform = sp->dev_specific; 86 struct device *dev = sp->dev; 87 struct platform_device *pdev = to_platform_device(dev); 88 int ret; 89 90 sp_platform->irq_count = platform_irq_count(pdev); 91 92 ret = platform_get_irq(pdev, 0); 93 if (ret < 0) { 94 dev_notice(dev, "unable to get IRQ (%d)\n", ret); 95 return ret; 96 } 97 98 sp->psp_irq = ret; 99 if (sp_platform->irq_count == 1) { 100 sp->ccp_irq = ret; 101 } else { 102 ret = platform_get_irq(pdev, 1); 103 if (ret < 0) { 104 dev_notice(dev, "unable to get IRQ (%d)\n", ret); 105 return ret; 106 } 107 108 sp->ccp_irq = ret; 109 } 110 111 return 0; 112} 113 114static int sp_platform_probe(struct platform_device *pdev) 115{ 116 struct sp_device *sp; 117 struct sp_platform *sp_platform; 118 struct device *dev = &pdev->dev; 119 enum dev_dma_attr attr; 120 int ret; 121 122 ret = -ENOMEM; 123 sp = sp_alloc_struct(dev); 124 if (!sp) 125 goto e_err; 126 127 sp_platform = devm_kzalloc(dev, sizeof(*sp_platform), GFP_KERNEL); 128 if (!sp_platform) 129 goto e_err; 130 131 sp->dev_specific = sp_platform; 132 sp->dev_vdata = pdev->dev.of_node ? sp_get_of_version(pdev) 133 : sp_get_acpi_version(pdev); 134 if (!sp->dev_vdata) { 135 ret = -ENODEV; 136 dev_err(dev, "missing driver data\n"); 137 goto e_err; 138 } 139 140 sp->io_map = devm_platform_ioremap_resource(pdev, 0); 141 if (IS_ERR(sp->io_map)) { 142 ret = PTR_ERR(sp->io_map); 143 goto e_err; 144 } 145 146 attr = device_get_dma_attr(dev); 147 if (attr == DEV_DMA_NOT_SUPPORTED) { 148 dev_err(dev, "DMA is not supported"); 149 goto e_err; 150 } 151 152 sp_platform->coherent = (attr == DEV_DMA_COHERENT); 153 if (sp_platform->coherent) 154 sp->axcache = CACHE_WB_NO_ALLOC; 155 else 156 sp->axcache = CACHE_NONE; 157 158 ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(48)); 159 if (ret) { 160 dev_err(dev, "dma_set_mask_and_coherent failed (%d)\n", ret); 161 goto e_err; 162 } 163 164 ret = sp_get_irqs(sp); 165 if (ret) 166 goto e_err; 167 168 dev_set_drvdata(dev, sp); 169 170 ret = sp_init(sp); 171 if (ret) 172 goto e_err; 173 174 dev_notice(dev, "enabled\n"); 175 176 return 0; 177 178e_err: 179 dev_notice(dev, "initialization failed\n"); 180 return ret; 181} 182 183static int sp_platform_remove(struct platform_device *pdev) 184{ 185 struct device *dev = &pdev->dev; 186 struct sp_device *sp = dev_get_drvdata(dev); 187 188 sp_destroy(sp); 189 190 dev_notice(dev, "disabled\n"); 191 192 return 0; 193} 194 195#ifdef CONFIG_PM 196static int sp_platform_suspend(struct platform_device *pdev, 197 pm_message_t state) 198{ 199 struct device *dev = &pdev->dev; 200 struct sp_device *sp = dev_get_drvdata(dev); 201 202 return sp_suspend(sp); 203} 204 205static int sp_platform_resume(struct platform_device *pdev) 206{ 207 struct device *dev = &pdev->dev; 208 struct sp_device *sp = dev_get_drvdata(dev); 209 210 return sp_resume(sp); 211} 212#endif 213 214static struct platform_driver sp_platform_driver = { 215 .driver = { 216 .name = "ccp", 217#ifdef CONFIG_ACPI 218 .acpi_match_table = sp_acpi_match, 219#endif 220#ifdef CONFIG_OF 221 .of_match_table = sp_of_match, 222#endif 223 }, 224 .probe = sp_platform_probe, 225 .remove = sp_platform_remove, 226#ifdef CONFIG_PM 227 .suspend = sp_platform_suspend, 228 .resume = sp_platform_resume, 229#endif 230}; 231 232int sp_platform_init(void) 233{ 234 return platform_driver_register(&sp_platform_driver); 235} 236 237void sp_platform_exit(void) 238{ 239 platform_driver_unregister(&sp_platform_driver); 240}