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