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