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 #ifdef CONFIG_ACPI 43 static const struct acpi_device_id sp_acpi_match[] = { 44 { "AMDI0C00", (kernel_ulong_t)&dev_vdata[0] }, 45 { }, 46 }; 47 MODULE_DEVICE_TABLE(acpi, sp_acpi_match); 48 #endif 49 50 #ifdef CONFIG_OF 51 static const struct of_device_id sp_of_match[] = { 52 { .compatible = "amd,ccp-seattle-v1a", 53 .data = (const void *)&dev_vdata[0] }, 54 { }, 55 }; 56 MODULE_DEVICE_TABLE(of, sp_of_match); 57 #endif 58 59 static 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 71 static 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 83 static 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 unsigned int i, count; 89 int ret; 90 91 for (i = 0, count = 0; i < pdev->num_resources; i++) { 92 struct resource *res = &pdev->resource[i]; 93 94 if (resource_type(res) == IORESOURCE_IRQ) 95 count++; 96 } 97 98 sp_platform->irq_count = count; 99 100 ret = platform_get_irq(pdev, 0); 101 if (ret < 0) { 102 dev_notice(dev, "unable to get IRQ (%d)\n", ret); 103 return ret; 104 } 105 106 sp->psp_irq = ret; 107 if (count == 1) { 108 sp->ccp_irq = ret; 109 } else { 110 ret = platform_get_irq(pdev, 1); 111 if (ret < 0) { 112 dev_notice(dev, "unable to get IRQ (%d)\n", ret); 113 return ret; 114 } 115 116 sp->ccp_irq = ret; 117 } 118 119 return 0; 120 } 121 122 static int sp_platform_probe(struct platform_device *pdev) 123 { 124 struct sp_device *sp; 125 struct sp_platform *sp_platform; 126 struct device *dev = &pdev->dev; 127 enum dev_dma_attr attr; 128 struct resource *ior; 129 int ret; 130 131 ret = -ENOMEM; 132 sp = sp_alloc_struct(dev); 133 if (!sp) 134 goto e_err; 135 136 sp_platform = devm_kzalloc(dev, sizeof(*sp_platform), GFP_KERNEL); 137 if (!sp_platform) 138 goto e_err; 139 140 sp->dev_specific = sp_platform; 141 sp->dev_vdata = pdev->dev.of_node ? sp_get_of_version(pdev) 142 : sp_get_acpi_version(pdev); 143 if (!sp->dev_vdata) { 144 ret = -ENODEV; 145 dev_err(dev, "missing driver data\n"); 146 goto e_err; 147 } 148 149 ior = platform_get_resource(pdev, IORESOURCE_MEM, 0); 150 sp->io_map = devm_ioremap_resource(dev, ior); 151 if (IS_ERR(sp->io_map)) { 152 ret = PTR_ERR(sp->io_map); 153 goto e_err; 154 } 155 156 attr = device_get_dma_attr(dev); 157 if (attr == DEV_DMA_NOT_SUPPORTED) { 158 dev_err(dev, "DMA is not supported"); 159 goto e_err; 160 } 161 162 sp_platform->coherent = (attr == DEV_DMA_COHERENT); 163 if (sp_platform->coherent) 164 sp->axcache = CACHE_WB_NO_ALLOC; 165 else 166 sp->axcache = CACHE_NONE; 167 168 ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(48)); 169 if (ret) { 170 dev_err(dev, "dma_set_mask_and_coherent failed (%d)\n", ret); 171 goto e_err; 172 } 173 174 ret = sp_get_irqs(sp); 175 if (ret) 176 goto e_err; 177 178 dev_set_drvdata(dev, sp); 179 180 ret = sp_init(sp); 181 if (ret) 182 goto e_err; 183 184 dev_notice(dev, "enabled\n"); 185 186 return 0; 187 188 e_err: 189 dev_notice(dev, "initialization failed\n"); 190 return ret; 191 } 192 193 static int sp_platform_remove(struct platform_device *pdev) 194 { 195 struct device *dev = &pdev->dev; 196 struct sp_device *sp = dev_get_drvdata(dev); 197 198 sp_destroy(sp); 199 200 dev_notice(dev, "disabled\n"); 201 202 return 0; 203 } 204 205 #ifdef CONFIG_PM 206 static int sp_platform_suspend(struct platform_device *pdev, 207 pm_message_t state) 208 { 209 struct device *dev = &pdev->dev; 210 struct sp_device *sp = dev_get_drvdata(dev); 211 212 return sp_suspend(sp, state); 213 } 214 215 static int sp_platform_resume(struct platform_device *pdev) 216 { 217 struct device *dev = &pdev->dev; 218 struct sp_device *sp = dev_get_drvdata(dev); 219 220 return sp_resume(sp); 221 } 222 #endif 223 224 static struct platform_driver sp_platform_driver = { 225 .driver = { 226 .name = "ccp", 227 #ifdef CONFIG_ACPI 228 .acpi_match_table = sp_acpi_match, 229 #endif 230 #ifdef CONFIG_OF 231 .of_match_table = sp_of_match, 232 #endif 233 }, 234 .probe = sp_platform_probe, 235 .remove = sp_platform_remove, 236 #ifdef CONFIG_PM 237 .suspend = sp_platform_suspend, 238 .resume = sp_platform_resume, 239 #endif 240 }; 241 242 int sp_platform_init(void) 243 { 244 return platform_driver_register(&sp_platform_driver); 245 } 246 247 void sp_platform_exit(void) 248 { 249 platform_driver_unregister(&sp_platform_driver); 250 } 251