1 // SPDX-License-Identifier: GPL-2.0-only
3 * AMD Secure Processor device driver
5 * Copyright (C) 2014,2018 Advanced Micro Devices, Inc.
7 * Author: Tom Lendacky <thomas.lendacky@amd.com>
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>
23 #include <linux/of_address.h>
24 #include <linux/acpi.h>
30 unsigned int irq_count
;
33 static const struct sp_dev_vdata dev_vdata
[] = {
36 #ifdef CONFIG_CRYPTO_DEV_SP_CCP
37 .ccp_vdata
= &ccpv3_platform
,
43 static const struct acpi_device_id sp_acpi_match
[] = {
44 { "AMDI0C00", (kernel_ulong_t
)&dev_vdata
[0] },
47 MODULE_DEVICE_TABLE(acpi
, sp_acpi_match
);
51 static const struct of_device_id sp_of_match
[] = {
52 { .compatible
= "amd,ccp-seattle-v1a",
53 .data
= (const void *)&dev_vdata
[0] },
56 MODULE_DEVICE_TABLE(of
, sp_of_match
);
59 static struct sp_dev_vdata
*sp_get_of_version(struct platform_device
*pdev
)
62 const struct of_device_id
*match
;
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
;
71 static struct sp_dev_vdata
*sp_get_acpi_version(struct platform_device
*pdev
)
74 const struct acpi_device_id
*match
;
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
;
83 static int sp_get_irqs(struct sp_device
*sp
)
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
;
91 for (i
= 0, count
= 0; i
< pdev
->num_resources
; i
++) {
92 struct resource
*res
= &pdev
->resource
[i
];
94 if (resource_type(res
) == IORESOURCE_IRQ
)
98 sp_platform
->irq_count
= count
;
100 ret
= platform_get_irq(pdev
, 0);
102 dev_notice(dev
, "unable to get IRQ (%d)\n", ret
);
110 ret
= platform_get_irq(pdev
, 1);
112 dev_notice(dev
, "unable to get IRQ (%d)\n", ret
);
122 static int sp_platform_probe(struct platform_device
*pdev
)
124 struct sp_device
*sp
;
125 struct sp_platform
*sp_platform
;
126 struct device
*dev
= &pdev
->dev
;
127 enum dev_dma_attr attr
;
131 sp
= sp_alloc_struct(dev
);
135 sp_platform
= devm_kzalloc(dev
, sizeof(*sp_platform
), GFP_KERNEL
);
139 sp
->dev_specific
= sp_platform
;
140 sp
->dev_vdata
= pdev
->dev
.of_node
? sp_get_of_version(pdev
)
141 : sp_get_acpi_version(pdev
);
142 if (!sp
->dev_vdata
) {
144 dev_err(dev
, "missing driver data\n");
148 sp
->io_map
= devm_platform_ioremap_resource(pdev
, 0);
149 if (IS_ERR(sp
->io_map
)) {
150 ret
= PTR_ERR(sp
->io_map
);
154 attr
= device_get_dma_attr(dev
);
155 if (attr
== DEV_DMA_NOT_SUPPORTED
) {
156 dev_err(dev
, "DMA is not supported");
160 sp_platform
->coherent
= (attr
== DEV_DMA_COHERENT
);
161 if (sp_platform
->coherent
)
162 sp
->axcache
= CACHE_WB_NO_ALLOC
;
164 sp
->axcache
= CACHE_NONE
;
166 ret
= dma_set_mask_and_coherent(dev
, DMA_BIT_MASK(48));
168 dev_err(dev
, "dma_set_mask_and_coherent failed (%d)\n", ret
);
172 ret
= sp_get_irqs(sp
);
176 dev_set_drvdata(dev
, sp
);
182 dev_notice(dev
, "enabled\n");
187 dev_notice(dev
, "initialization failed\n");
191 static int sp_platform_remove(struct platform_device
*pdev
)
193 struct device
*dev
= &pdev
->dev
;
194 struct sp_device
*sp
= dev_get_drvdata(dev
);
198 dev_notice(dev
, "disabled\n");
204 static int sp_platform_suspend(struct platform_device
*pdev
,
207 struct device
*dev
= &pdev
->dev
;
208 struct sp_device
*sp
= dev_get_drvdata(dev
);
210 return sp_suspend(sp
, state
);
213 static int sp_platform_resume(struct platform_device
*pdev
)
215 struct device
*dev
= &pdev
->dev
;
216 struct sp_device
*sp
= dev_get_drvdata(dev
);
218 return sp_resume(sp
);
222 static struct platform_driver sp_platform_driver
= {
226 .acpi_match_table
= sp_acpi_match
,
229 .of_match_table
= sp_of_match
,
232 .probe
= sp_platform_probe
,
233 .remove
= sp_platform_remove
,
235 .suspend
= sp_platform_suspend
,
236 .resume
= sp_platform_resume
,
240 int sp_platform_init(void)
242 return platform_driver_register(&sp_platform_driver
);
245 void sp_platform_exit(void)
247 platform_driver_unregister(&sp_platform_driver
);